From 5daeda890c2f98a152fbecd8a6fca06df3545006 Mon Sep 17 00:00:00 2001 From: Ammar Ahmed Date: Wed, 22 Nov 2023 11:16:15 +0500 Subject: [PATCH] mobile: push changes --- .../app/common/database/sqlite.kysely.ts | 2 +- .../mobile/app/components/container/index.tsx | 2 - apps/mobile/app/components/header/index.tsx | 100 ++++-- .../app/components/header/left-menus.tsx | 18 +- .../app/components/header/right-menus.tsx | 46 +-- apps/mobile/app/components/header/title.tsx | 89 ++--- .../list-items/headers/section-header.tsx | 3 +- .../app/components/list-items/note/index.tsx | 2 +- apps/mobile/app/components/list/empty.tsx | 172 +++++----- apps/mobile/app/components/list/index.tsx | 1 + .../app/components/list/list-item.wrapper.tsx | 2 +- .../app/components/properties/notebooks.js | 74 +---- .../app/components/selection-header/index.js | 29 +- .../components/sheets/add-notebook/index.tsx | 20 +- .../app/components/sheets/add-to/context.js | 29 -- .../components/sheets/add-to/filtered-list.js | 76 ----- .../app/components/sheets/add-to/index.tsx | 292 +++++++---------- .../sheets/add-to/list-header-item.js | 88 ----- .../app/components/sheets/add-to/list-item.js | 293 ----------------- .../sheets/add-to/notebook-item.tsx | 236 ++++++++++++++ .../app/components/sheets/add-to/store.ts | 37 +-- .../components/sheets/manage-tags/index.tsx | 303 +++++++++++------- .../sheets/notebook-sheet/index.tsx | 56 ++-- .../app/components/sheets/sort/index.js | 5 +- .../components/side-menu/color-section.tsx | 2 +- .../app/components/side-menu/menu-item.js | 13 +- .../components/side-menu/pinned-section.tsx | 14 +- apps/mobile/app/hooks/use-actions.tsx | 22 +- apps/mobile/app/hooks/use-db-item.ts | 8 +- apps/mobile/app/hooks/use-navigation-focus.ts | 9 + apps/mobile/app/hooks/use-notebook.ts | 10 +- .../mobile/app/navigation/navigation-stack.js | 55 +--- apps/mobile/app/screens/favorites/index.tsx | 55 ++-- apps/mobile/app/screens/home/index.tsx | 68 ++-- apps/mobile/app/screens/notebook/index.tsx | 95 ++---- apps/mobile/app/screens/notebooks/index.tsx | 79 ++--- apps/mobile/app/screens/notes/colored.tsx | 24 +- apps/mobile/app/screens/notes/common.ts | 8 + apps/mobile/app/screens/notes/index.tsx | 216 ++++--------- apps/mobile/app/screens/notes/monographs.tsx | 34 +- apps/mobile/app/screens/notes/tagged.tsx | 23 +- apps/mobile/app/screens/notes/topic-notes.tsx | 104 ------ apps/mobile/app/screens/reminders/index.tsx | 86 ++--- apps/mobile/app/screens/search/index.js | 78 ----- apps/mobile/app/screens/search/index.tsx | 84 +++++ apps/mobile/app/screens/search/search-bar.js | 148 --------- apps/mobile/app/screens/search/search-bar.tsx | 94 ++++++ .../app/screens/settings/editor/state.ts | 17 +- apps/mobile/app/screens/settings/group.tsx | 55 ++-- apps/mobile/app/screens/settings/home.tsx | 103 +++--- apps/mobile/app/screens/settings/index.tsx | 30 +- apps/mobile/app/screens/tags/index.tsx | 58 ++-- apps/mobile/app/screens/trash/index.tsx | 63 ++-- apps/mobile/app/services/navigation.ts | 49 +-- .../mobile/app/stores/item-selection-store.ts | 71 ++++ .../mobile/app/stores/use-navigation-store.ts | 84 ++--- .../ios/extension.bundle/clipper.bundle.js | 2 +- apps/theme-builder/package-lock.json | 2 +- 58 files changed, 1637 insertions(+), 2201 deletions(-) delete mode 100644 apps/mobile/app/components/sheets/add-to/context.js delete mode 100644 apps/mobile/app/components/sheets/add-to/filtered-list.js delete mode 100644 apps/mobile/app/components/sheets/add-to/list-header-item.js delete mode 100644 apps/mobile/app/components/sheets/add-to/list-item.js create mode 100644 apps/mobile/app/components/sheets/add-to/notebook-item.tsx delete mode 100644 apps/mobile/app/screens/notes/topic-notes.tsx delete mode 100644 apps/mobile/app/screens/search/index.js create mode 100644 apps/mobile/app/screens/search/index.tsx delete mode 100644 apps/mobile/app/screens/search/search-bar.js create mode 100644 apps/mobile/app/screens/search/search-bar.tsx create mode 100644 apps/mobile/app/stores/item-selection-store.ts diff --git a/apps/mobile/app/common/database/sqlite.kysely.ts b/apps/mobile/app/common/database/sqlite.kysely.ts index 6c19f2144..1ac2fb407 100644 --- a/apps/mobile/app/common/database/sqlite.kysely.ts +++ b/apps/mobile/app/common/database/sqlite.kysely.ts @@ -108,7 +108,7 @@ class RNSqliteConnection implements DatabaseConnection { : "exec"; const result = await this.db.executeAsync(sql, parameters as any[]); - console.log("SQLITE result:", result?.rows?._array); + // console.log("SQLITE result:", result?.rows?._array); if (mode === "query" || !result.insertId) return { rows: result.rows?._array || [] diff --git a/apps/mobile/app/components/container/index.tsx b/apps/mobile/app/components/container/index.tsx index e15361aa9..1ca6c6f29 100644 --- a/apps/mobile/app/components/container/index.tsx +++ b/apps/mobile/app/components/container/index.tsx @@ -22,7 +22,6 @@ import { KeyboardAvoidingView, Platform } from "react-native"; import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets"; import useIsFloatingKeyboard from "../../hooks/use-is-floating-keyboard"; import { useSettingStore } from "../../stores/use-setting-store"; -import { Header } from "../header"; import SelectionHeader from "../selection-header"; export const Container = ({ children }: PropsWithChildren) => { @@ -46,7 +45,6 @@ export const Container = ({ children }: PropsWithChildren) => { {!introCompleted ? null : ( <> -
)} diff --git a/apps/mobile/app/components/header/index.tsx b/apps/mobile/app/components/header/index.tsx index 99e981a78..3c811a366 100644 --- a/apps/mobile/app/components/header/index.tsx +++ b/apps/mobile/app/components/header/index.tsx @@ -20,39 +20,70 @@ along with this program. If not, see . import React, { useCallback, useEffect, useState } from "react"; import { Platform, StyleSheet, View } from "react-native"; import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets"; -import { SearchBar } from "../../screens/search/search-bar"; import { eSubscribeEvent, eUnSubscribeEvent } from "../../services/event-manager"; -import useNavigationStore from "../../stores/use-navigation-store"; import { useSelectionStore } from "../../stores/use-selection-store"; import { useThemeColors } from "@notesnook/theme"; import { eScrollEvent } from "../../utils/events"; import { LeftMenus } from "./left-menus"; import { RightMenus } from "./right-menus"; import { Title } from "./title"; +import useNavigationStore, { + RouteName +} from "../../stores/use-navigation-store"; -const _Header = () => { +type HeaderRightButton = { + title: string; + onPress: () => void; +}; + +export const Header = ({ + renderedInRoute, + onLeftMenuButtonPress, + title, + titleHiddenOnRender, + headerRightButtons, + id, + accentColor, + isBeta, + canGoBack, + onPressDefaultRightButton, + hasSearch, + onSearch +}: { + onLeftMenuButtonPress?: () => void; + renderedInRoute: RouteName; + id?: string; + title: string; + headerRightButtons?: HeaderRightButton[]; + titleHiddenOnRender?: boolean; + accentColor?: string; + isBeta?: boolean; + canGoBack?: boolean; + onPressDefaultRightButton?: () => void; + hasSearch?: boolean; + onSearch?: () => void; +}) => { const { colors } = useThemeColors(); const insets = useGlobalSafeAreaInsets(); - const [hide, setHide] = useState(true); + const [borderHidden, setBorderHidden] = useState(true); const selectionMode = useSelectionStore((state) => state.selectionMode); - const currentScreen = useNavigationStore( - (state) => state.currentScreen?.name - ); + const isFocused = useNavigationStore((state) => state.focusedRouteId === id); const onScroll = useCallback( - (data: { x: number; y: number }) => { + (data: { x: number; y: number; id?: string; route: string }) => { + if (data.route !== renderedInRoute || data.id !== id) return; if (data.y > 150) { - if (!hide) return; - setHide(false); + if (!borderHidden) return; + setBorderHidden(false); } else { - if (hide) return; - setHide(true); + if (borderHidden) return; + setBorderHidden(true); } }, - [hide] + [borderHidden, id, renderedInRoute] ); useEffect(() => { @@ -60,9 +91,9 @@ const _Header = () => { return () => { eUnSubscribeEvent(eScrollEvent, onScroll); }; - }, [hide, onScroll]); + }, [borderHidden, onScroll]); - return selectionMode ? null : ( + return selectionMode && isFocused ? null : ( <> { backgroundColor: colors.primary.background, overflow: "hidden", borderBottomWidth: 1, - borderBottomColor: hide + borderBottomColor: borderHidden ? "transparent" : colors.secondary.background, justifyContent: "space-between" } ]} > - {currentScreen === "Search" ? ( - - ) : ( - <> - - - - </View> - <RightMenus /> - </> - )} + <> + <View style={styles.leftBtnContainer}> + <LeftMenus + canGoBack={canGoBack} + onLeftButtonPress={onLeftMenuButtonPress} + /> + + <Title + isHiddenOnRender={titleHiddenOnRender} + renderedInRoute={renderedInRoute} + id={id} + accentColor={accentColor} + title={title} + isBeta={isBeta} + /> + </View> + <RightMenus + renderedInRoute={renderedInRoute} + id={id} + headerRightButtons={headerRightButtons} + onPressDefaultRightButton={onPressDefaultRightButton} + search={hasSearch} + onSearch={onSearch} + /> + </> </View> </> ); }; -export const Header = React.memo(_Header, () => true); const styles = StyleSheet.create({ container: { diff --git a/apps/mobile/app/components/header/left-menus.tsx b/apps/mobile/app/components/header/left-menus.tsx index 5da228b8c..58d95ecf9 100644 --- a/apps/mobile/app/components/header/left-menus.tsx +++ b/apps/mobile/app/components/header/left-menus.tsx @@ -17,23 +17,29 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +import { useThemeColors } from "@notesnook/theme"; import React from "react"; import { notesnook } from "../../../e2e/test.ids"; import { DDS } from "../../services/device-detection"; import Navigation from "../../services/navigation"; -import useNavigationStore from "../../stores/use-navigation-store"; import { useSettingStore } from "../../stores/use-setting-store"; -import { useThemeColors } from "@notesnook/theme"; import { tabBarRef } from "../../utils/global-refs"; import { IconButton } from "../ui/icon-button"; -export const LeftMenus = () => { +export const LeftMenus = ({ + canGoBack, + onLeftButtonPress +}: { + canGoBack?: boolean; + onLeftButtonPress?: () => void; +}) => { const { colors } = useThemeColors(); const deviceMode = useSettingStore((state) => state.deviceMode); - const canGoBack = useNavigationStore((state) => state.canGoBack); const isTablet = deviceMode === "tablet"; - const onLeftButtonPress = () => { + const _onLeftButtonPress = () => { + if (onLeftButtonPress) return onLeftButtonPress(); + if (!canGoBack) { if (tabBarRef.current?.isDrawerOpen()) { Navigation.closeDrawer(); @@ -60,7 +66,7 @@ export const LeftMenus = () => { left={40} top={40} right={DDS.isLargeTablet() ? 10 : 10} - onPress={onLeftButtonPress} + onPress={_onLeftButtonPress} onLongPress={() => { Navigation.popToTop(); }} diff --git a/apps/mobile/app/components/header/right-menus.tsx b/apps/mobile/app/components/header/right-menus.tsx index a379a515b..afc6fb8dd 100644 --- a/apps/mobile/app/components/header/right-menus.tsx +++ b/apps/mobile/app/components/header/right-menus.tsx @@ -20,40 +20,46 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. import React, { useRef } from "react"; import { Platform, StyleSheet, View } from "react-native"; //@ts-ignore +import { useThemeColors } from "@notesnook/theme"; import Menu from "react-native-reanimated-material-menu"; import { notesnook } from "../../../e2e/test.ids"; import Navigation from "../../services/navigation"; import SearchService from "../../services/search"; -import useNavigationStore from "../../stores/use-navigation-store"; +import { + HeaderRightButton, + RouteName +} from "../../stores/use-navigation-store"; import { useSettingStore } from "../../stores/use-setting-store"; -import { useThemeColors } from "@notesnook/theme"; import { SIZE } from "../../utils/size"; import { sleep } from "../../utils/time"; import { Button } from "../ui/button"; import { IconButton } from "../ui/icon-button"; -export const RightMenus = () => { +export const RightMenus = ({ + headerRightButtons, + renderedInRoute, + id, + onPressDefaultRightButton, + search, + onSearch +}: { + headerRightButtons?: HeaderRightButton[]; + renderedInRoute: RouteName; + id?: string; + onPressDefaultRightButton?: () => void; + search?: boolean; + onSearch?: () => void; +}) => { const { colors } = useThemeColors(); const { colors: contextMenuColors } = useThemeColors("contextMenu"); const deviceMode = useSettingStore((state) => state.deviceMode); - const buttons = useNavigationStore((state) => state.headerRightButtons); - const currentScreen = useNavigationStore((state) => state.currentScreen.name); - const buttonAction = useNavigationStore((state) => state.buttonAction); const menuRef = useRef<Menu>(null); return ( <View style={styles.rightBtnContainer}> - {!currentScreen.startsWith("Settings") ? ( + {search ? ( <IconButton - onPress={async () => { - SearchService.prepareSearch(); - Navigation.navigate( - { - name: "Search" - }, - {} - ); - }} + onPress={onSearch} testID="icon-search" name="magnify" color={colors.primary.paragraph} @@ -63,9 +69,9 @@ export const RightMenus = () => { {deviceMode !== "mobile" ? ( <Button - onPress={buttonAction} + onPress={onPressDefaultRightButton} testID={notesnook.ids.default.addBtn} - icon={currentScreen === "Trash" ? "delete" : "plus"} + icon={renderedInRoute === "Trash" ? "delete" : "plus"} iconSize={SIZE.xl} type="shade" hitSlop={{ @@ -86,7 +92,7 @@ export const RightMenus = () => { /> ) : null} - {buttons && buttons.length > 0 ? ( + {headerRightButtons && headerRightButtons.length > 0 ? ( <Menu ref={menuRef} animationDuration={200} @@ -108,7 +114,7 @@ export const RightMenus = () => { /> } > - {buttons.map((item) => ( + {headerRightButtons.map((item) => ( <Button style={{ width: 150, diff --git a/apps/mobile/app/components/header/title.tsx b/apps/mobile/app/components/header/title.tsx index e0ee64041..989185e36 100644 --- a/apps/mobile/app/components/header/title.tsx +++ b/apps/mobile/app/components/header/title.tsx @@ -20,105 +20,74 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. import { useThemeColors } from "@notesnook/theme"; import React, { useCallback, useEffect, useState } from "react"; import { Platform } from "react-native"; -import { db } from "../../common/database"; -import NotebookScreen from "../../screens/notebook"; import { eSubscribeEvent, eUnSubscribeEvent } from "../../services/event-manager"; -import useNavigationStore from "../../stores/use-navigation-store"; import { eScrollEvent } from "../../utils/events"; import { SIZE } from "../../utils/size"; import Tag from "../ui/tag"; import Heading from "../ui/typography/heading"; -const titleState: { [id: string]: boolean } = {}; - -export const Title = () => { +export const Title = ({ + title, + isHiddenOnRender, + accentColor, + isBeta, + renderedInRoute, + id +}: { + title: string; + isHiddenOnRender?: boolean; + accentColor?: string; + isBeta?: boolean; + renderedInRoute: string; + id?: string; +}) => { const { colors } = useThemeColors(); - const currentScreen = useNavigationStore((state) => state.currentScreen); - const isNotebook = currentScreen.name === "Notebook"; - const isTopic = currentScreen?.name === "TopicNotes"; - const [hide, setHide] = useState( - isNotebook - ? typeof titleState[currentScreen.id as string] === "boolean" - ? titleState[currentScreen.id as string] - : true - : false - ); - const isHidden = titleState[currentScreen.id as string]; - const notebook = - isTopic && currentScreen.notebookId - ? db.notebooks?.notebook(currentScreen.notebookId)?.data - : null; - const title = currentScreen.title; - const isTag = currentScreen?.name === "TaggedNotes"; - + const [visible, setVisible] = useState(isHiddenOnRender); + const isTag = title.startsWith("#"); const onScroll = useCallback( - (data: { x: number; y: number }) => { - if (currentScreen.name !== "Notebook") { - setHide(false); - return; - } + (data: { x: number; y: number; id?: string; route: string }) => { + if (data.route !== renderedInRoute || data.id !== id) return; if (data.y > 150) { - if (!hide) return; - titleState[currentScreen.id as string] = false; - setHide(false); + if (!visible) return; + setVisible(false); } else { - if (hide) return; - titleState[currentScreen.id as string] = true; - setHide(true); + if (visible) return; + setVisible(true); } }, - [currentScreen.id, currentScreen.name, hide] + [id, renderedInRoute, visible] ); - useEffect(() => { - if (currentScreen.name === "Notebook") { - const value = - typeof titleState[currentScreen.id] === "boolean" - ? titleState[currentScreen.id] - : true; - setHide(value); - } else { - setHide(titleState[currentScreen.id as string]); - } - }, [currentScreen.id, currentScreen.name]); - useEffect(() => { eSubscribeEvent(eScrollEvent, onScroll); return () => { eUnSubscribeEvent(eScrollEvent, onScroll); }; - }, [hide, onScroll]); + }, [visible, onScroll]); - function navigateToNotebook() { - if (!isTopic) return; - if (notebook) { - NotebookScreen.navigate(notebook, true); - } - } return ( <> - {!hide && !isHidden ? ( + {!visible ? ( <Heading - onPress={navigateToNotebook} numberOfLines={1} size={SIZE.lg} style={{ flexWrap: "wrap", marginTop: Platform.OS === "ios" ? -1 : 0 }} - color={currentScreen.color || colors.primary.heading} + color={accentColor || colors.primary.heading} > {isTag ? ( <Heading size={SIZE.xl} color={colors.primary.accent}> # </Heading> ) : null} - {title}{" "} + {isTag ? title.slice(1) : title}{" "} <Tag - visible={currentScreen.beta} + visible={isBeta} text="BETA" style={{ backgroundColor: "transparent" diff --git a/apps/mobile/app/components/list-items/headers/section-header.tsx b/apps/mobile/app/components/list-items/headers/section-header.tsx index 0cffb13b8..f418180c2 100644 --- a/apps/mobile/app/components/list-items/headers/section-header.tsx +++ b/apps/mobile/app/components/list-items/headers/section-header.tsx @@ -120,6 +120,7 @@ export const SectionHeader = React.memo< <> <Button onPress={() => { + console.log("Opening Sort sheet", screen, dataType); presentSheet({ component: <Sort screen={screen} type={dataType} /> }); @@ -170,7 +171,7 @@ export const SectionHeader = React.memo< SettingsService.set({ [dataType !== "notebook" ? "notesListMode" - : "notebooksListMode"]: isCompactModeEnabled + : "notebooksListMode"]: !isCompactModeEnabled ? "compact" : "normal" }); diff --git a/apps/mobile/app/components/list-items/note/index.tsx b/apps/mobile/app/components/list-items/note/index.tsx index 8f4e6c80a..611c1d7ed 100644 --- a/apps/mobile/app/components/list-items/note/index.tsx +++ b/apps/mobile/app/components/list-items/note/index.tsx @@ -106,7 +106,7 @@ const NoteItem = ({ {notebooks?.items ?.filter( (item) => - item.id !== useNavigationStore.getState().currentScreen?.id + item.id !== useNavigationStore.getState().currentRoute?.id ) .map((item) => ( <Button diff --git a/apps/mobile/app/components/list/empty.tsx b/apps/mobile/app/components/list/empty.tsx index 26f809568..9fe287c31 100644 --- a/apps/mobile/app/components/list/empty.tsx +++ b/apps/mobile/app/components/list/empty.tsx @@ -49,98 +49,96 @@ type EmptyListProps = { screen?: string; }; -export const Empty = React.memo( - function Empty({ - loading = true, - placeholder, - title, - color, - dataType, - screen - }: EmptyListProps) { - const { colors } = useThemeColors(); - const insets = useGlobalSafeAreaInsets(); - const { height } = useWindowDimensions(); - const introCompleted = useSettingStore( - (state) => state.settings.introCompleted - ); +export const Empty = React.memo(function Empty({ + loading = true, + placeholder, + title, + color, + dataType, + screen +}: EmptyListProps) { + const { colors } = useThemeColors(); + const insets = useGlobalSafeAreaInsets(); + const { height } = useWindowDimensions(); + const introCompleted = useSettingStore( + (state) => state.settings.introCompleted + ); - const tip = useTip( - screen === "Notes" && introCompleted - ? "first-note" - : placeholder?.type || ((dataType + "s") as any), - screen === "Notes" ? "notes" : "list" - ); + const tip = useTip( + screen === "Notes" && introCompleted + ? "first-note" + : placeholder?.type || ((dataType + "s") as any), + screen === "Notes" ? "notes" : "list" + ); - return ( - <View - style={[ - { - height: height - (140 + insets.top), - width: "80%", - justifyContent: "center", - alignSelf: "center" - } - ]} - > - {!loading ? ( - <> - <Tip - color={color ? color : "accent"} - tip={tip || ({ text: placeholder?.paragraph } as TTip)} + return ( + <View + style={[ + { + height: height - (140 + insets.top), + width: "80%", + justifyContent: "center", + alignSelf: "center" + } + ]} + > + {!loading ? ( + <> + <Tip + color={color} + tip={ + screen !== "Search" + ? tip || ({ text: placeholder?.paragraph } as TTip) + : ({ text: placeholder?.paragraph } as TTip) + } + style={{ + backgroundColor: "transparent", + paddingHorizontal: 0 + }} + /> + {placeholder?.button && ( + <Button + testID={notesnook.buttons.add} + type="grayAccent" + title={placeholder?.button} + iconPosition="right" + icon="arrow-right" + onPress={placeholder?.action} + buttonType={{ + text: color || colors.primary.accent + }} style={{ - backgroundColor: "transparent", - paddingHorizontal: 0 + alignSelf: "flex-start", + borderRadius: 5, + height: 40 }} /> - {placeholder?.button && ( - <Button - testID={notesnook.buttons.add} - type="grayAccent" - title={placeholder?.button} - iconPosition="right" - icon="arrow-right" - onPress={placeholder?.action} - buttonType={{ - text: color || colors.primary.accent - }} - style={{ - alignSelf: "flex-start", - borderRadius: 5, - height: 40 - }} - /> - )} - </> - ) : ( - <> - <View - style={{ - alignSelf: "center", - alignItems: "flex-start", - width: "100%" - }} - > - <Heading>{placeholder?.title}</Heading> - <Paragraph size={SIZE.sm} textBreakStrategy="balanced"> - {placeholder?.loading} - </Paragraph> - <Seperator /> - <ActivityIndicator - size={SIZE.lg} - color={color || colors.primary.accent} - /> - </View> - </> - )} - </View> - ); - }, - (prev, next) => { - if (prev.loading === next.loading) return true; - return false; - } -); + )} + </> + ) : ( + <> + <View + style={{ + alignSelf: "center", + alignItems: "flex-start", + width: "100%" + }} + > + <Heading>{placeholder?.title}</Heading> + <Paragraph size={SIZE.sm} textBreakStrategy="balanced"> + {placeholder?.loading} + </Paragraph> + <Seperator /> + <ActivityIndicator + size={SIZE.lg} + color={color || colors.primary.accent} + /> + </View> + </> + )} + </View> + ); +}); /** * Make a tips manager. diff --git a/apps/mobile/app/components/list/index.tsx b/apps/mobile/app/components/list/index.tsx index efee3a5e8..0563c3dcc 100644 --- a/apps/mobile/app/components/list/index.tsx +++ b/apps/mobile/app/components/list/index.tsx @@ -201,6 +201,7 @@ export default function List(props: ListProps) { dataType={props.dataType} color={props.customAccentColor} placeholder={props.placeholder} + screen={props.renderedInRoute} /> ) : null } diff --git a/apps/mobile/app/components/list/list-item.wrapper.tsx b/apps/mobile/app/components/list/list-item.wrapper.tsx index 600024ab7..4badb6a4f 100644 --- a/apps/mobile/app/components/list/list-item.wrapper.tsx +++ b/apps/mobile/app/components/list/list-item.wrapper.tsx @@ -251,7 +251,7 @@ async function resolveNotes(ids: string[]) { group.notebooks.map((id) => resolved.notebooks[id]) ), attachmentsCount: - (await db.attachments?.ofNote(noteId, "all"))?.length || 0 + (await db.attachments?.ofNote(noteId, "all").ids())?.length || 0 }; } return data; diff --git a/apps/mobile/app/components/properties/notebooks.js b/apps/mobile/app/components/properties/notebooks.js index e8d72b845..1d7c27f2d 100644 --- a/apps/mobile/app/components/properties/notebooks.js +++ b/apps/mobile/app/components/properties/notebooks.js @@ -17,39 +17,28 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +import { useThemeColors } from "@notesnook/theme"; import React, { useEffect, useState } from "react"; -import { ScrollView, View } from "react-native"; +import { View } from "react-native"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; import { db } from "../../common/database"; import NotebookScreen from "../../screens/notebook"; -import { TopicNotes } from "../../screens/notes/topic-notes"; -import { - eSendEvent, - presentSheet, - ToastManager -} from "../../services/event-manager"; -import Navigation from "../../services/navigation"; -import { useNotebookStore } from "../../stores/use-notebook-store"; -import { useThemeColors } from "@notesnook/theme"; +import { eSendEvent, presentSheet } from "../../services/event-manager"; +import { eClearEditor } from "../../utils/events"; import { SIZE } from "../../utils/size"; import { Button } from "../ui/button"; import Heading from "../ui/typography/heading"; -import { eClearEditor } from "../../utils/events"; export default function Notebooks({ note, close, full }) { const { colors } = useThemeColors(); - const notebooks = useNotebookStore((state) => state.notebooks); async function getNotebooks(item) { let filteredNotebooks = []; const relations = await db.relations.to(note, "notebook").resolve(); - filteredNotebooks.push(relations); - if (!item.notebooks || item.notebooks.length < 1) return filteredNotebooks; return filteredNotebooks; } const [noteNotebooks, setNoteNotebooks] = useState([]); - useEffect(() => { getNotebooks().then((notebooks) => setNoteNotebooks(notebooks)); }); @@ -60,11 +49,6 @@ export default function Notebooks({ note, close, full }) { NotebookScreen.navigate(item, true); }; - const navigateTopic = (id, notebookId) => { - let item = db.notebooks.notebook(notebookId)?.topics?.topic(id)?._topic; - if (!item) return; - TopicNotes.navigate(item, true); - }; const renderItem = (item) => ( <View key={item.id} @@ -105,56 +89,6 @@ export default function Notebooks({ note, close, full }) { > {item.title} </Heading> - - <ScrollView - horizontal={true} - showsHorizontalScrollIndicator={false} - style={{ - flexDirection: "row", - marginLeft: 8, - borderLeftColor: colors.primary.hover, - borderLeftWidth: 1, - paddingLeft: 8 - }} - > - {item.topics.map((topic) => ( - <Button - key={topic.id} - onPress={() => { - navigateTopic(topic.id, item.id); - eSendEvent(eClearEditor); - close(); - }} - onLongPress={async () => { - await db.notes.removeFromNotebook( - { - id: item.id, - topic: topic.id - }, - note - ); - useNotebookStore.getState().setNotebooks(); - Navigation.queueRoutesForUpdate(); - ToastManager.show({ - heading: "Note removed from topic", - context: "local", - type: "success" - }); - }} - title={topic.title} - type="gray" - height={30} - fontSize={SIZE.xs} - icon="bookmark-outline" - style={{ - marginRight: 5, - borderRadius: 100, - paddingHorizontal: 8 - }} - /> - ))} - <View style={{ width: 10 }} /> - </ScrollView> </View> ); diff --git a/apps/mobile/app/components/selection-header/index.js b/apps/mobile/app/components/selection-header/index.js index bc1bcad78..d9ffa9b03 100644 --- a/apps/mobile/app/components/selection-header/index.js +++ b/apps/mobile/app/components/selection-header/index.js @@ -46,8 +46,7 @@ export const SelectionHeader = React.memo(() => { ); const setSelectionMode = useSelectionStore((state) => state.setSelectionMode); const clearSelection = useSelectionStore((state) => state.clearSelection); - const currentScreen = useNavigationStore((state) => state.currentScreen); - const screen = currentScreen.name; + const currentRoute = useNavigationStore((state) => state.currentRoute); const insets = useGlobalSafeAreaInsets(); SearchService.prepareSearch?.(); const allItems = SearchService.getSearchInformation()?.get() || []; @@ -205,9 +204,9 @@ export const SelectionHeader = React.memo(() => { size={SIZE.xl} /> - {screen === "Trash" || - screen === "Notebooks" || - screen === "Reminders" ? null : ( + {currentRoute === "Trash" || + currentRoute === "Notebooks" || + currentRoute === "Reminders" ? null : ( <> <IconButton onPress={async () => { @@ -256,17 +255,15 @@ export const SelectionHeader = React.memo(() => { </> )} - {screen === "TopicNotes" || screen === "Notebook" ? ( + {currentRoute === "Notebook" ? ( <IconButton onPress={async () => { if (selectedItemsList.length > 0) { - const currentScreen = - useNavigationStore.getState().currentScreen; - - if (screen === "Notebook") { + const { focusedRouteId } = useNavigationStore.getState(); + if (currentRoute === "Notebook") { for (const item of selectedItemsList) { await db.relations.unlink( - { type: "notebook", id: currentScreen.id }, + { type: "notebook", id: focusedRouteId }, item ); } @@ -287,9 +284,7 @@ export const SelectionHeader = React.memo(() => { customStyle={{ marginLeft: 10 }} - tooltipText={`Remove from ${ - screen === "Notebook" ? "notebook" : "topic" - }`} + tooltipText={`Remove from Notebook`} tooltipPosition={4} testID="select-minus" color={colors.primary.paragraph} @@ -298,7 +293,7 @@ export const SelectionHeader = React.memo(() => { /> ) : null} - {screen === "Favorites" ? ( + {currentRoute === "Favorites" ? ( <IconButton onPress={addToFavorite} customStyle={{ @@ -312,7 +307,7 @@ export const SelectionHeader = React.memo(() => { /> ) : null} - {screen === "Trash" ? null : ( + {currentRoute === "Trash" ? null : ( <IconButton customStyle={{ marginLeft: 10 @@ -328,7 +323,7 @@ export const SelectionHeader = React.memo(() => { /> )} - {screen === "Trash" ? ( + {currentRoute === "Trash" ? ( <> <IconButton customStyle={{ diff --git a/apps/mobile/app/components/sheets/add-notebook/index.tsx b/apps/mobile/app/components/sheets/add-notebook/index.tsx index f6000a7d8..628a6c0ec 100644 --- a/apps/mobile/app/components/sheets/add-notebook/index.tsx +++ b/apps/mobile/app/components/sheets/add-notebook/index.tsx @@ -38,6 +38,7 @@ import Seperator from "../../ui/seperator"; import Heading from "../../ui/typography/heading"; import { MoveNotes } from "../move-notes/movenote"; import { eOnNotebookUpdated } from "../../../utils/events"; +import { getParentNotebookId } from "../../../utils/notebooks"; export const AddNotebookSheet = ({ notebook, @@ -84,9 +85,12 @@ export const AddNotebookSheet = ({ useMenuStore.getState().setMenuPins(); Navigation.queueRoutesForUpdate(); useRelationStore.getState().update(); - eSendEvent(eOnNotebookUpdated, parentNotebook?.id); if (notebook) { - eSendEvent(eOnNotebookUpdated, notebook.id); + const parent = await getParentNotebookId(notebook.id); + eSendEvent(eOnNotebookUpdated, parent); + setImmediate(() => { + eSendEvent(eOnNotebookUpdated, notebook.id); + }); } if (!notebook) { @@ -136,6 +140,11 @@ export const AddNotebookSheet = ({ onChangeText={(value) => { title.current = value; }} + onLayout={() => { + setImmediate(() => { + titleInput?.current?.focus(); + }); + }} placeholder="Enter a title" onSubmit={() => { descriptionInput.current?.focus(); @@ -160,8 +169,13 @@ export const AddNotebookSheet = ({ ); }; -AddNotebookSheet.present = (notebook?: Notebook, parentNotebook?: Notebook) => { +AddNotebookSheet.present = ( + notebook?: Notebook, + parentNotebook?: Notebook, + context?: string +) => { presentSheet({ + context: context, component: (ref, close) => ( <AddNotebookSheet notebook={notebook} diff --git a/apps/mobile/app/components/sheets/add-to/context.js b/apps/mobile/app/components/sheets/add-to/context.js deleted file mode 100644 index 550ecc00a..000000000 --- a/apps/mobile/app/components/sheets/add-to/context.js +++ /dev/null @@ -1,29 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -import { createContext, useContext } from "react"; - -export const SelectionContext = createContext({ - toggleSelection: (item) => {}, - deselect: (item) => {}, - select: (item) => {}, - deselectAll: () => {} -}); -export const SelectionProvider = SelectionContext.Provider; -export const useSelectionContext = () => useContext(SelectionContext); diff --git a/apps/mobile/app/components/sheets/add-to/filtered-list.js b/apps/mobile/app/components/sheets/add-to/filtered-list.js deleted file mode 100644 index a4be1c1fd..000000000 --- a/apps/mobile/app/components/sheets/add-to/filtered-list.js +++ /dev/null @@ -1,76 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -import React, { useCallback, useEffect, useRef, useState } from "react"; -import { FlashList } from "react-native-actions-sheet"; -import { db } from "../../../common/database"; -import { ListHeaderInputItem } from "./list-header-item.js"; - -export const FilteredList = ({ - data, - itemType, - onAddItem, - hasHeaderSearch, - listRef, - ...restProps -}) => { - const [filtered, setFiltered] = useState(data); - const query = useRef(); - const onChangeText = useCallback( - (value) => { - query.current = value; - try { - if (!value) return setFiltered(data); - const results = db.lookup[itemType + "s"]([...data], value); - setFiltered(results); - } catch (e) { - console.warn(e.message); - } - }, - [data, itemType] - ); - const onSubmit = async (value) => { - return await onAddItem(value); - }; - - useEffect(() => { - onChangeText(query.current); - }, [data, onChangeText]); - - return ( - <FlashList - {...restProps} - data={filtered} - ref={listRef} - ListHeaderComponent={ - hasHeaderSearch ? ( - <ListHeaderInputItem - onSubmit={onSubmit} - onChangeText={onChangeText} - itemType={itemType} - testID={"list-input" + itemType} - placeholder={`Search or add a new ${itemType}`} - /> - ) : null - } - keyboardShouldPersistTaps="always" - keyboardDismissMode="none" - /> - ); -}; diff --git a/apps/mobile/app/components/sheets/add-to/index.tsx b/apps/mobile/app/components/sheets/add-to/index.tsx index 2c5a81536..cbc90f5f5 100644 --- a/apps/mobile/app/components/sheets/add-to/index.tsx +++ b/apps/mobile/app/components/sheets/add-to/index.tsx @@ -17,12 +17,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -import { Note, Notebook } from "@notesnook/core"; +import { GroupHeader, Note } from "@notesnook/core"; import { useThemeColors } from "@notesnook/theme"; -import React, { RefObject, useCallback, useEffect, useMemo } from "react"; +import React, { RefObject, useCallback, useEffect } from "react"; import { Keyboard, TouchableOpacity, View } from "react-native"; -import { ActionSheetRef } from "react-native-actions-sheet"; -import Icon from "react-native-vector-icons/MaterialCommunityIcons"; +import { ActionSheetRef, FlashList } from "react-native-actions-sheet"; import { db } from "../../../common/database"; import { eSendEvent, presentSheet } from "../../../services/event-manager"; import Navigation from "../../../services/navigation"; @@ -36,24 +35,53 @@ import { Dialog } from "../../dialog"; import DialogHeader from "../../dialog/dialog-header"; import { Button } from "../../ui/button"; import Paragraph from "../../ui/typography/paragraph"; -import { SelectionProvider } from "./context"; -import { FilteredList } from "./filtered-list"; -import { ListItem } from "./list-item"; -import { useItemSelectionStore } from "./store"; +import { NotebookItem } from "./notebook-item"; +import { useNotebookItemSelectionStore } from "./store"; +import SheetProvider from "../../sheet-provider"; +import { ItemSelection } from "../../../stores/item-selection-store"; + +async function updateInitialSelectionState(items: string[]) { + const relations = await db.relations + .to( + { + type: "note", + ids: items + }, + "notebook" + ) + .get(); + + const initialSelectionState: ItemSelection = {}; + const notebookIds = [ + ...new Set(relations.map((relation) => relation.fromId)) + ]; + + for (const id of notebookIds) { + const all = items.every((noteId) => { + return ( + relations.findIndex( + (relation) => relation.fromId === id && relation.toId === noteId + ) > -1 + ); + }); + if (all) { + initialSelectionState[id] = "selected"; + } else { + initialSelectionState[id] = "intermediate"; + } + } + useNotebookItemSelectionStore.setState({ + initialState: initialSelectionState, + selection: { ...initialSelectionState }, + multiSelect: relations.length > 1 + }); +} -/** - * Render all notebooks - * Render sub notebooks - * fix selection, remove topics stuff. - * show already selected notebooks regardless of their level - * show intermediate selection for nested notebooks at all levels. - * @returns - */ const MoveNoteSheet = ({ note, actionSheetRef }: { - note: Note; + note: Note | undefined; actionSheetRef: RefObject<ActionSheetRef>; }) => { const { colors } = useThemeColors(); @@ -63,72 +91,42 @@ const MoveNoteSheet = ({ (state) => state.selectedItemsList ); const setNotebooks = useNotebookStore((state) => state.setNotebooks); - - const multiSelect = useItemSelectionStore((state) => state.multiSelect); + const multiSelect = useNotebookItemSelectionStore( + (state) => state.multiSelect + ); useEffect(() => { + const items = note + ? [note.id] + : (selectedItemsList as Note[]).map((note) => note.id); + updateInitialSelectionState(items); return () => { - useItemSelectionStore.getState().setMultiSelect(false); - useItemSelectionStore.getState().setItemState({}); + useNotebookItemSelectionStore.setState({ + initialState: {}, + selection: {}, + multiSelect: false, + canEnableMultiSelectMode: true + }); }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const updateItemState = useCallback(function ( - item: Notebook, - state: "selected" | "intermediate" | "deselected" - ) { - const itemState = { ...useItemSelectionStore.getState().itemState }; - const mergeState = { - [item.id]: state - }; - useItemSelectionStore.getState().setItemState({ - ...itemState, - ...mergeState - }); - }, - []); - - const contextValue = useMemo( - () => ({ - toggleSelection: (item: Notebook) => { - const itemState = useItemSelectionStore.getState().itemState; - if (itemState[item.id] === "selected") { - updateItemState(item, "deselected"); - } else { - updateItemState(item, "selected"); - } - }, - deselect: (item: Notebook) => { - updateItemState(item, "deselected"); - }, - select: (item: Notebook) => { - updateItemState(item, "selected"); - }, - deselectAll: () => { - useItemSelectionStore.setState({ - itemState: {} - }); - } - }), - [updateItemState] - ); + }, [note, selectedItemsList]); const onSave = async () => { const noteIds = note ? [note.id] : selectedItemsList.map((n) => (n as Note).id); - const itemState = useItemSelectionStore.getState().itemState; - for (const id in itemState) { + + const changedNotebooks = useNotebookItemSelectionStore.getState().selection; + + for (const id in changedNotebooks) { const item = await db.notebooks.notebook(id); if (!item) continue; - if (itemState[id] === "selected") { - for (let noteId of noteIds) { - await db.relations.add(item, { id: noteId, type: "note" }); + if (changedNotebooks[id] === "selected") { + for (const id of noteIds) { + await db.relations.add(item, { id: id, type: "note" }); } - } else if (itemState[id] === "deselected") { - for (let noteId of noteIds) { - await db.relations.unlink(item, { id: noteId, type: "note" }); + } else if (changedNotebooks[id] === "deselected") { + for (const id of noteIds) { + await db.relations.unlink(item, { id: id, type: "note" }); } } } @@ -141,9 +139,18 @@ const MoveNoteSheet = ({ actionSheetRef.current?.hide(); }; + const renderNotebook = useCallback( + ({ item, index }: { item: string | GroupHeader; index: number }) => + (item as GroupHeader).type === "header" ? null : ( + <NotebookItem items={notebooks} id={item as string} index={index} /> + ), + [notebooks] + ); + return ( <> <Dialog context="move_note" /> + <SheetProvider context="link-notebooks" /> <View> <TouchableOpacity style={{ @@ -204,127 +211,50 @@ const MoveNoteSheet = ({ }} type="grayAccent" onPress={() => { - useItemSelectionStore.setState({ - itemState: {} - }); + const items = note + ? [note.id] + : (selectedItemsList as Note[]).map((note) => note.id); + updateInitialSelectionState(items); }} /> </View> - <SelectionProvider value={contextValue}> - <View + <View + style={{ + paddingHorizontal: 12, + maxHeight: dimensions.height * 0.85, + height: 50 * ((notebooks?.ids.length || 0) + 2) + }} + > + <FlashList + data={notebooks?.ids?.filter((id) => typeof id === "string")} style={{ - paddingHorizontal: 12, - maxHeight: dimensions.height * 0.85, - height: 50 * ((notebooks?.ids.length || 0) + 2) + width: "100%" }} - > - <FilteredList - ListEmptyComponent={ - notebooks?.ids.length ? null : ( - <View - style={{ - width: "100%", - height: "100%", - justifyContent: "center", - alignItems: "center" - }} - > - <Icon - name="book-outline" - color={colors.primary.icon} - size={100} - /> - <Paragraph style={{ marginBottom: 10 }}> - You do not have any notebooks. - </Paragraph> - </View> - ) - } - estimatedItemSize={50} - data={notebooks?.ids.length} - hasHeaderSearch={true} - renderItem={({ item, index }) => ( - <ListItem - item={item} - key={item.id} - index={index} - hasNotes={getSelectedNotesCountInItem(item) > 0} - sheetRef={actionSheetRef} - infoText={ - <> - {item.topics.length === 1 - ? item.topics.length + " topic" - : item.topics.length + " topics"} - </> - } - getListItems={getItemsForItem} - getSublistItemProps={(topic) => ({ - hasNotes: getSelectedNotesCountInItem(topic) > 0, - style: { - marginBottom: 0, - height: 40 - }, - onPress: (item) => { - const itemState = - useItemSelectionStore.getState().itemState; - const currentState = itemState[item.id]; - if (currentState !== "selected") { - resetItemState("deselected"); - contextValue.select(item); - } else { - contextValue.deselect(item); - } - }, - key: item.id, - type: "transparent" - })} - icon={(expanded) => ({ - name: expanded ? "chevron-up" : "chevron-down", - color: expanded - ? colors.primary.accent - : colors.primary.paragraph - })} - onScrollEnd={() => { - actionSheetRef.current?.handleChildScrollEnd(); - }} - hasSubList={true} - hasHeaderSearch={false} - type="grayBg" - sublistItemType="topic" - onAddItem={(title) => { - return onAddTopic(title, item); - }} - onAddSublistItem={(item) => { - openAddTopicDialog(item); - }} - onPress={(item) => { - const itemState = - useItemSelectionStore.getState().itemState; - const currentState = itemState[item.id]; - if (currentState !== "selected") { - resetItemState("deselected"); - contextValue.select(item); - } else { - contextValue.deselect(item); - } - }} - /> - )} - itemType="notebook" - onAddItem={async (title) => { - return await onAddNotebook(title); - }} - ListFooterComponent={<View style={{ height: 20 }} />} - /> - </View> - </SelectionProvider> + estimatedItemSize={50} + keyExtractor={(item) => item as string} + renderItem={renderNotebook} + ListEmptyComponent={ + <View + style={{ + flex: 1, + justifyContent: "center", + alignItems: "center", + height: 200 + }} + > + <Paragraph color={colors.primary.icon}>No notebooks</Paragraph> + </View> + } + ListFooterComponent={<View style={{ height: 50 }} />} + /> + </View> </View> </> ); }; -MoveNoteSheet.present = (note) => { +MoveNoteSheet.present = (note?: Note) => { presentSheet({ component: (ref) => <MoveNoteSheet actionSheetRef={ref} note={note} />, enableGesturesInScrollView: false, diff --git a/apps/mobile/app/components/sheets/add-to/list-header-item.js b/apps/mobile/app/components/sheets/add-to/list-header-item.js deleted file mode 100644 index e5260fa93..000000000 --- a/apps/mobile/app/components/sheets/add-to/list-header-item.js +++ /dev/null @@ -1,88 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -import React, { useRef, useState } from "react"; -import { View } from "react-native"; -import Input from "../../ui/input"; -import Paragraph from "../../ui/typography/paragraph"; -import { useThemeColors } from "@notesnook/theme"; - -export const ListHeaderInputItem = ({ - onSubmit, - onChangeText, - placeholder, - testID -}) => { - const [focused, setFocused] = useState(false); - const { colors } = useThemeColors("sheet"); - - const [inputValue, setInputValue] = useState(); - const inputRef = useRef(); - return ( - <View - style={{ - width: "100%", - marginTop: 10, - marginBottom: 5 - }} - > - <Input - fwdRef={inputRef} - onChangeText={(value) => { - setInputValue(value); - onChangeText?.(value); - }} - testID={testID} - blurOnSubmit={false} - onFocusInput={() => { - setFocused(true); - }} - onBlurInput={() => { - setFocused(false); - }} - button={{ - icon: inputValue ? "plus" : "magnify", - color: focused ? colors.selected.icon : colors.secondary.icon, - onPress: async () => { - const result = await onSubmit(inputValue); - if (result) { - inputRef.current?.blur(); - } - } - }} - placeholder={placeholder} - marginBottom={5} - /> - {inputValue ? ( - <View - style={{ - backgroundColor: colors.primary.shade, - padding: 5, - borderRadius: 5, - marginBottom: 10 - }} - > - <Paragraph color={colors.primary.accent}> - Tap on + to add {`"${inputValue}"`} - </Paragraph> - </View> - ) : null} - </View> - ); -}; diff --git a/apps/mobile/app/components/sheets/add-to/list-item.js b/apps/mobile/app/components/sheets/add-to/list-item.js deleted file mode 100644 index 157c71a05..000000000 --- a/apps/mobile/app/components/sheets/add-to/list-item.js +++ /dev/null @@ -1,293 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -import { useThemeColors } from "@notesnook/theme"; -import React, { useEffect, useState } from "react"; -import { View } from "react-native"; -import { db } from "../../../common/database"; -import { useSelectionStore } from "../../../stores/use-selection-store"; -import { SIZE } from "../../../utils/size"; -import { IconButton } from "../../ui/icon-button"; -import { PressableButton } from "../../ui/pressable"; -import Heading from "../../ui/typography/heading"; -import Paragraph from "../../ui/typography/paragraph"; -import { useSelectionContext } from "./context"; -import { FilteredList } from "./filtered-list"; -import { useItemSelectionStore } from "./store"; - -const SelectionIndicator = ({ - item, - hasNotes, - selectItem, - onPress, - onChange -}) => { - const itemState = useItemSelectionStore((state) => state.itemState[item.id]); - const multiSelect = useItemSelectionStore((state) => state.multiSelect); - - const isSelected = itemState === "selected"; - const isIntermediate = itemState === "intermediate"; - const isRemoved = !isSelected && hasNotes; - const { colors } = useThemeColors("sheet"); - - useEffect(() => { - onChange?.(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [itemState]); - - return ( - <IconButton - size={22} - customStyle={{ - marginRight: 5, - width: 23, - height: 23 - }} - color={ - isRemoved - ? colors.static.red - : isIntermediate || isSelected - ? colors.selected.icon - : colors.primary.icon - } - onPress={() => { - if (multiSelect) return selectItem(); - onPress?.(item); - }} - onLongPress={() => { - useItemSelectionStore.getState().setMultiSelect(true); - selectItem(); - }} - testID={ - isRemoved - ? "close-circle-outline" - : isSelected - ? "check-circle-outline" - : isIntermediate - ? "minus-circle-outline" - : "checkbox-blank-circle-outline" - } - name={ - isRemoved - ? "close-circle-outline" - : isSelected - ? "check-circle-outline" - : isIntermediate - ? "minus-circle-outline" - : "checkbox-blank-circle-outline" - } - /> - ); -}; - -export const ListItem = ({ - item, - index, - icon, - infoText, - hasSubList, - onPress, - onScrollEnd, - getListItems, - style, - type, - sublistItemType, - onAddItem, - getSublistItemProps, - hasHeaderSearch, - onAddSublistItem, - hasNotes, - onChange, - sheetRef -}) => { - const { toggleSelection } = useSelectionContext(); - const multiSelect = useItemSelectionStore((state) => state.multiSelect); - const [showSelectedIndicator, setShowSelectedIndicator] = useState(false); - const { colors } = useThemeColors("sheet"); - const [expanded, setExpanded] = useState(false); - - function selectItem() { - toggleSelection(item); - } - - const getSelectedNotesCountInNotebookTopics = (item) => { - if (item.type === "topic") return; - - let count = 0; - const noteIds = []; - for (let topic of item.topics) { - noteIds.push(...(db.notes?.topicReferences.get(topic.id) || [])); - if (useItemSelectionStore.getState().itemState[topic.id] === "selected") { - count++; - } - } - useSelectionStore.getState().selectedItemsList.forEach((item) => { - if (noteIds.indexOf(item.id) > -1) { - count++; - } - }); - return count; - }; - - useEffect(() => { - setShowSelectedIndicator(getSelectedNotesCountInNotebookTopics(item) > 0); - }, [item]); - - const onChangeSubItem = () => { - setShowSelectedIndicator(getSelectedNotesCountInNotebookTopics(item) > 0); - }; - - return ( - <View - style={{ - overflow: "hidden", - marginBottom: 10, - ...style - }} - > - <PressableButton - onPress={() => { - if (hasSubList) return setExpanded(!expanded); - if (multiSelect) return selectItem(); - onPress?.(item); - }} - type={type} - onLongPress={() => { - useItemSelectionStore.getState().setMultiSelect(true); - selectItem(); - }} - customStyle={{ - height: style?.height || 50, - width: "100%", - alignItems: "flex-start" - }} - > - <View - style={{ - width: "100%", - height: 50, - justifyContent: "space-between", - flexDirection: "row", - alignItems: "center", - paddingHorizontal: 12 - }} - > - <View - style={{ - flexDirection: "row", - alignItems: "center" - }} - > - <SelectionIndicator - hasNotes={hasNotes} - onPress={onPress} - item={item} - onChange={onChange} - selectItem={selectItem} - /> - <View> - {hasSubList && expanded ? ( - <Heading size={SIZE.md}>{item.title}</Heading> - ) : ( - <Paragraph size={SIZE.sm}>{item.title}</Paragraph> - )} - - {infoText ? ( - <Paragraph size={SIZE.xs} color={colors.primary.icon}> - {infoText} - </Paragraph> - ) : null} - </View> - </View> - - <View - style={{ - flexDirection: "row", - alignItems: "center" - }} - > - {showSelectedIndicator ? ( - <View - style={{ - backgroundColor: colors.primary.accent, - width: 7, - height: 7, - borderRadius: 100, - marginRight: 12 - }} - /> - ) : null} - - {onAddSublistItem ? ( - <IconButton - name={"plus"} - testID="add-item-icon" - color={colors.primary.paragraph} - size={SIZE.xl} - onPress={() => { - onAddSublistItem(item); - }} - /> - ) : null} - {icon ? ( - <IconButton - name={icon(expanded).name} - color={icon(expanded).color} - size={icon(expanded).size || SIZE.xl} - onPress={ - hasSubList - ? () => setExpanded(!expanded) - : icon(expanded).onPress - } - /> - ) : null} - </View> - </View> - </PressableButton> - - {expanded && hasSubList ? ( - <FilteredList - nestedScrollEnabled - data={getListItems(item)} - keyboardShouldPersistTaps="always" - keyboardDismissMode="none" - onMomentumScrollEnd={onScrollEnd} - style={{ - width: "95%", - alignSelf: "flex-end", - maxHeight: 250 - }} - estimatedItemSize={40} - itemType={sublistItemType} - hasHeaderSearch={hasHeaderSearch} - renderItem={({ item, index }) => ( - <ListItem - item={item} - {...getSublistItemProps(item)} - index={index} - onChange={onChangeSubItem} - onScrollEnd={onScrollEnd} - /> - )} - onAddItem={onAddItem} - /> - ) : null} - </View> - ); -}; diff --git a/apps/mobile/app/components/sheets/add-to/notebook-item.tsx b/apps/mobile/app/components/sheets/add-to/notebook-item.tsx new file mode 100644 index 000000000..d0548aeb2 --- /dev/null +++ b/apps/mobile/app/components/sheets/add-to/notebook-item.tsx @@ -0,0 +1,236 @@ +/* +This file is part of the Notesnook project (https://notesnook.com/) + +Copyright (C) 2023 Streetwriters (Private) Limited + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +import { Notebook, VirtualizedGrouping } from "@notesnook/core"; +import { useThemeColors } from "@notesnook/theme"; +import React, { useMemo } from "react"; +import { View, useWindowDimensions } from "react-native"; +import { notesnook } from "../../../../e2e/test.ids"; +import { useTotalNotes } from "../../../hooks/use-db-item"; +import { useNotebook } from "../../../hooks/use-notebook"; +import useNavigationStore from "../../../stores/use-navigation-store"; +import { SIZE } from "../../../utils/size"; +import { IconButton } from "../../ui/icon-button"; +import { PressableButton } from "../../ui/pressable"; +import Paragraph from "../../ui/typography/paragraph"; +import { AddNotebookSheet } from "../add-notebook"; +import { + useNotebookExpandedStore, + useNotebookItemSelectionStore +} from "./store"; + +type NotebookParentProp = { + parent?: NotebookParentProp; + item?: Notebook; +}; + +export const NotebookItem = ({ + id, + currentLevel = 0, + index, + parent, + items +}: { + id: string; + currentLevel?: number; + index: number; + parent?: NotebookParentProp; + items?: VirtualizedGrouping<Notebook>; +}) => { + const { nestedNotebooks, notebook: item } = useNotebook(id, items); + const ids = useMemo(() => (id ? [id] : []), [id]); + const { totalNotes: totalNotes } = useTotalNotes(ids, "notebook"); + const screen = useNavigationStore((state) => state.currentRoute); + const { colors } = useThemeColors("sheet"); + const selection = useNotebookItemSelectionStore((state) => + id ? state.selection[id] : undefined + ); + const isSelected = selection === "selected"; + const isFocused = screen.id === id; + const { fontScale } = useWindowDimensions(); + const expanded = useNotebookExpandedStore((state) => state.expanded[id]); + + const onPress = () => { + if (!item) return; + const state = useNotebookItemSelectionStore.getState(); + + if (isSelected) { + state.markAs(item, !state.initialState[id] ? undefined : "deselected"); + return; + } + + if (!state.multiSelect) { + const keys = Object.keys(state.selection); + const nextState: any = {}; + for (const key in keys) { + nextState[key] = !state.initialState[key] ? undefined : "deselected"; + } + console.log("Single item selection"); + state.setSelection({ + [item.id]: "selected", + ...nextState + }); + } else { + console.log("Multi item selection"); + state.markAs(item, "selected"); + } + }; + + return ( + <View + style={{ + paddingLeft: currentLevel > 0 && currentLevel < 6 ? 15 : undefined, + width: "100%" + }} + > + <PressableButton + type={"transparent"} + onLongPress={() => { + if (!item) return; + useNotebookItemSelectionStore.setState({ + multiSelect: true + }); + useNotebookItemSelectionStore.getState().markAs(item, "selected"); + }} + testID={`add-to-notebook-item-${currentLevel}-${index}`} + onPress={onPress} + customStyle={{ + justifyContent: "space-between", + width: "100%", + alignItems: "center", + flexDirection: "row", + paddingLeft: 0, + paddingRight: 12, + borderRadius: 0 + }} + > + <View + style={{ + flexDirection: "row", + alignItems: "center" + }} + > + <IconButton + size={SIZE.lg} + color={ + isSelected + ? colors.selected.icon + : selection === "deselected" + ? colors.error.accent + : colors.primary.icon + } + onPress={onPress} + top={0} + left={0} + bottom={0} + right={0} + customStyle={{ + width: 40, + height: 40 + }} + name={ + selection === "deselected" + ? "close-circle-outline" + : isSelected + ? "check-circle-outline" + : selection === "intermediate" + ? "minus-circle-outline" + : "checkbox-blank-circle-outline" + } + /> + + {nestedNotebooks?.ids.length ? ( + <IconButton + size={SIZE.lg} + color={isSelected ? colors.selected.icon : colors.primary.icon} + onPress={() => { + useNotebookExpandedStore.getState().setExpanded(id); + }} + top={0} + left={0} + bottom={0} + right={0} + customStyle={{ + width: 40, + height: 40 + }} + name={expanded ? "chevron-down" : "chevron-right"} + /> + ) : ( + <> + <View + style={{ + width: 40, + height: 40 + }} + /> + </> + )} + + <Paragraph + color={ + isFocused ? colors.selected.paragraph : colors.secondary.paragraph + } + size={SIZE.sm} + > + {item?.title}{" "} + {totalNotes?.(id) ? ( + <Paragraph size={SIZE.xs} color={colors.secondary.paragraph}> + {totalNotes(id)} + </Paragraph> + ) : null} + </Paragraph> + </View> + <IconButton + name="plus" + customStyle={{ + width: 40 * fontScale, + height: 40 * fontScale + }} + testID={notesnook.ids.notebook.menu} + onPress={() => { + if (!item) return; + AddNotebookSheet.present(undefined, item, "link-notebooks"); + }} + left={0} + right={0} + bottom={0} + top={0} + color={colors.primary.icon} + size={SIZE.xl} + /> + </PressableButton> + + {!expanded + ? null + : nestedNotebooks?.ids.map((id, index) => ( + <NotebookItem + key={id as string} + id={id as string} + index={index} + currentLevel={currentLevel + 1} + items={nestedNotebooks} + parent={{ + parent: parent, + item: item + }} + /> + ))} + </View> + ); +}; diff --git a/apps/mobile/app/components/sheets/add-to/store.ts b/apps/mobile/app/components/sheets/add-to/store.ts index 827f47086..729afcbb7 100644 --- a/apps/mobile/app/components/sheets/add-to/store.ts +++ b/apps/mobile/app/components/sheets/add-to/store.ts @@ -16,27 +16,24 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -import create, { State } from "zustand"; +import create from "zustand"; +import { createItemSelectionStore } from "../../../stores/item-selection-store"; -type SelectionItemState = Record< - string, - "intermediate" | "selected" | "deselected" ->; - -export interface SelectionStore extends State { - itemState: SelectionItemState; - setItemState: (state: SelectionItemState) => void; - multiSelect: boolean; - setMultiSelect: (multiSelect: boolean) => void; -} - -export const useItemSelectionStore = create<SelectionStore>((set) => ({ - itemState: {}, - setItemState: (itemState) => { +export const useNotebookExpandedStore = create<{ + expanded: { + [id: string]: boolean; + }; + setExpanded: (id: string) => void; +}>((set, get) => ({ + expanded: {}, + setExpanded(id: string) { set({ - itemState + expanded: { + ...get().expanded, + [id]: !get().expanded[id] + } }); - }, - multiSelect: false, - setMultiSelect: (multiSelect) => set({ multiSelect }) + } })); + +export const useNotebookItemSelectionStore = createItemSelectionStore(true); diff --git a/apps/mobile/app/components/sheets/manage-tags/index.tsx b/apps/mobile/app/components/sheets/manage-tags/index.tsx index bd923c59e..e6b48377d 100644 --- a/apps/mobile/app/components/sheets/manage-tags/index.tsx +++ b/apps/mobile/app/components/sheets/manage-tags/index.tsx @@ -17,8 +17,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +import { VirtualizedGrouping } from "@notesnook/core"; import { Tags } from "@notesnook/core/dist/collections/tags"; -import { Note, Tag, isGroupHeader } from "@notesnook/core/dist/types"; +import { Note, Tag } from "@notesnook/core/dist/types"; import { useThemeColors } from "@notesnook/theme"; import React, { RefObject, @@ -28,12 +29,21 @@ import React, { useRef, useState } from "react"; -import { TextInput, View } from "react-native"; -import { ActionSheetRef, ScrollView } from "react-native-actions-sheet"; +import { TextInput, View, useWindowDimensions } from "react-native"; +import { + ActionSheetRef, + FlashList, + FlatList +} from "react-native-actions-sheet"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; import { db } from "../../../common/database"; +import { useDBItem } from "../../../hooks/use-db-item"; import { ToastManager, presentSheet } from "../../../services/event-manager"; import Navigation from "../../../services/navigation"; +import { + ItemSelection, + createItemSelectionStore +} from "../../../stores/item-selection-store"; import { useRelationStore } from "../../../stores/use-relation-store"; import { useTagStore } from "../../../stores/use-tag-store"; import { SIZE } from "../../../utils/size"; @@ -42,17 +52,40 @@ import Input from "../../ui/input"; import { PressableButton } from "../../ui/pressable"; import Heading from "../../ui/typography/heading"; import Paragraph from "../../ui/typography/paragraph"; -import { VirtualizedGrouping } from "@notesnook/core"; -function tagHasSomeNotes(tagId: string, noteIds: string[]) { - return db.relations.from({ type: "tag", id: tagId }, "note").has(...noteIds); +async function updateInitialSelectionState(items: string[]) { + const relations = await db.relations + .to( + { + type: "note", + ids: items + }, + "tag" + ) + .get(); + + const initialSelectionState: ItemSelection = {}; + const tagId = [...new Set(relations.map((relation) => relation.fromId))]; + + for (const id of tagId) { + const all = items.every((noteId) => { + return ( + relations.findIndex( + (relation) => relation.fromId === id && relation.toId === noteId + ) > -1 + ); + }); + if (all) { + initialSelectionState[id] = "selected"; + } else { + initialSelectionState[id] = "intermediate"; + } + } + + return initialSelectionState; } -function tagHasAllNotes(tagId: string, noteIds: string[]) { - return db.relations - .from({ type: "tag", id: tagId }, "note") - .hasAll(...noteIds); -} +const useTagItemSelection = createItemSelectionStore(true); const ManageTagsSheet = (props: { notes?: Note[]; @@ -60,12 +93,44 @@ const ManageTagsSheet = (props: { }) => { const { colors } = useThemeColors(); const notes = useMemo(() => props.notes || [], [props.notes]); - const tags = useTagStore((state) => state.tags); - + const [tags, setTags] = useState<VirtualizedGrouping<Tag>>(); const [query, setQuery] = useState<string>(); const inputRef = useRef<TextInput>(null); const [focus, setFocus] = useState(false); const [queryExists, setQueryExists] = useState(false); + const dimensions = useWindowDimensions(); + const refreshSelection = useCallback(() => { + const ids = notes.map((item) => item.id); + updateInitialSelectionState(ids).then((selection) => { + useTagItemSelection.setState({ + initialState: selection, + selection: { ...selection } + }); + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [notes, tags]); + + const refreshTags = useCallback(() => { + if (query && query.trim() !== "") { + db.lookup.tags(query).then((items) => { + setTags(items); + console.log("searched tags"); + }); + } else { + db.tags.all.sorted(db.settings.getGroupOptions("tags")).then((items) => { + console.log("items loaded tags"); + setTags(items); + }); + } + }, [query]); + + useEffect(() => { + refreshTags(); + }, [refreshTags, query]); + + useEffect(() => { + refreshSelection(); + }, [refreshSelection]); const checkQueryExists = (query: string) => { db.tags.all @@ -114,6 +179,7 @@ const ManageTagsSheet = (props: { useRelationStore.getState().update(); useTagStore.getState().setTags(); + refreshTags(); } catch (e) { ToastManager.show({ heading: "Cannot add tag", @@ -126,13 +192,64 @@ const ManageTagsSheet = (props: { Navigation.queueRoutesForUpdate(); }; + const onPress = useCallback( + async (id: string) => { + for (const note of notes) { + try { + if (!id) return; + const isSelected = + useTagItemSelection.getState().initialState[id] === "selected"; + if (isSelected) { + await db.relations.unlink( + { + id: id, + type: "tag" + }, + note + ); + } else { + await db.relations.add( + { + id: id, + type: "tag" + }, + note + ); + } + } catch (e) { + console.error(e); + } + } + useTagStore.getState().setTags(); + useRelationStore.getState().update(); + refreshTags(); + setTimeout(() => { + Navigation.queueRoutesForUpdate(); + }, 1); + refreshSelection(); + }, + [notes, refreshSelection, refreshTags] + ); + + const renderTag = useCallback( + ({ item }: { item: string; index: number }) => ( + <TagItem + key={item as string} + tags={tags as VirtualizedGrouping<Tag>} + id={item as string} + onPress={onPress} + /> + ), + [onPress, tags] + ); + return ( <View style={{ width: "100%", alignSelf: "center", paddingHorizontal: 12, - minHeight: focus ? "100%" : "60%" + maxHeight: dimensions.height * 0.85 }} > <Input @@ -161,31 +278,35 @@ const ManageTagsSheet = (props: { placeholder="Search or add a tag" /> - <ScrollView - overScrollMode="never" - scrollToOverflowEnabled={false} - keyboardDismissMode="none" - keyboardShouldPersistTaps="always" - > - {query && !queryExists ? ( - <PressableButton - key={"query_item"} - customStyle={{ - flexDirection: "row", - marginVertical: 5, - justifyContent: "space-between", - padding: 12 - }} - onPress={onSubmit} - type="selected" - > - <Heading size={SIZE.sm} color={colors.selected.heading}> - Add {'"' + "#" + query + '"'} - </Heading> - <Icon name="plus" color={colors.selected.icon} size={SIZE.lg} /> - </PressableButton> - ) : null} - {!tags || tags.ids.length === 0 ? ( + {query && !queryExists ? ( + <PressableButton + key={"query_item"} + customStyle={{ + flexDirection: "row", + marginVertical: 5, + justifyContent: "space-between", + padding: 12 + }} + onPress={onSubmit} + type="selected" + > + <Heading size={SIZE.sm} color={colors.selected.heading}> + Add {'"' + "#" + query + '"'} + </Heading> + <Icon name="plus" color={colors.selected.icon} size={SIZE.lg} /> + </PressableButton> + ) : null} + + <FlatList + data={tags?.ids?.filter((id) => typeof id === "string") as string[]} + style={{ + width: "100%" + }} + keyboardShouldPersistTaps + keyboardDismissMode="interactive" + keyExtractor={(item) => item as string} + renderItem={renderTag} + ListEmptyComponent={ <View style={{ width: "100%", @@ -204,19 +325,9 @@ const ManageTagsSheet = (props: { You do not have any tags. </Paragraph> </View> - ) : null} - - {tags?.ids - .filter((id) => !isGroupHeader(id)) - .map((item) => ( - <TagItem - key={item as string} - tags={tags} - id={item as string} - notes={notes} - /> - ))} - </ScrollView> + } + ListFooterComponent={<View style={{ height: 50 }} />} + /> </View> ); }; @@ -233,69 +344,17 @@ export default ManageTagsSheet; const TagItem = ({ id, - notes, - tags + tags, + onPress }: { id: string; - notes: Note[]; tags: VirtualizedGrouping<Tag>; + onPress: (id: string) => void; }) => { const { colors } = useThemeColors(); - const [tag, setTag] = useState<Tag>(); - const [selection, setSelection] = useState({ - all: false, - some: false - }); - const update = useRelationStore((state) => state.updater); + const [tag] = useDBItem(id, "tag", tags); + const selection = useTagItemSelection((state) => state.selection[id]); - const refresh = useCallback(() => { - tags.item(id).then(async (tag) => { - if (tag?.id) { - setSelection({ - all: await tagHasAllNotes( - tag.id, - notes.map((note) => note.id) - ), - some: await tagHasSomeNotes( - tag.id, - notes.map((note) => note.id) - ) - }); - } - setTag(tag); - }); - }, [id, tags, notes]); - - if (tag?.id !== id) { - refresh(); - } - - useEffect(() => { - if (tag?.id === id) { - refresh(); - } - }, [id, refresh, tag?.id, update]); - - const onPress = async () => { - for (const note of notes) { - try { - if (!tag?.id) return; - if (selection.all) { - await db.relations.unlink(tag, note); - } else { - await db.relations.add(tag, note); - } - } catch (e) { - console.error(e); - } - } - useTagStore.getState().setTags(); - useRelationStore.getState().update(); - setTimeout(() => { - Navigation.queueRoutesForUpdate(); - }, 1); - refresh(); - }; return ( <PressableButton customStyle={{ @@ -304,34 +363,32 @@ const TagItem = ({ justifyContent: "flex-start", height: 40 }} - onPress={onPress} + onPress={() => onPress(id)} type="gray" > {!tag ? null : ( - <IconButton + <Icon size={22} - customStyle={{ - marginRight: 5, - width: 23, - height: 23 - }} - onPress={onPress} + onPress={() => onPress(id)} color={ - selection.some || selection.all + selection === "selected" || selection === "intermediate" ? colors.selected.icon : colors.primary.icon } + style={{ + marginRight: 6 + }} testID={ - selection.all + selection === "selected" ? "check-circle-outline" - : selection.some + : selection === "intermediate" ? "minus-circle-outline" : "checkbox-blank-circle-outline" } name={ - selection.all + selection === "selected" ? "check-circle-outline" - : selection.some + : selection === "intermediate" ? "minus-circle-outline" : "checkbox-blank-circle-outline" } @@ -344,7 +401,7 @@ const TagItem = ({ style={{ width: 200, height: 30, - backgroundColor: colors.secondary.background, + // backgroundColor: colors.secondary.background, borderRadius: 5 }} /> diff --git a/apps/mobile/app/components/sheets/notebook-sheet/index.tsx b/apps/mobile/app/components/sheets/notebook-sheet/index.tsx index 7b25af93e..a0010d712 100644 --- a/apps/mobile/app/components/sheets/notebook-sheet/index.tsx +++ b/apps/mobile/app/components/sheets/notebook-sheet/index.tsx @@ -52,6 +52,24 @@ import Paragraph from "../../ui/typography/paragraph"; import { AddNotebookSheet } from "../add-notebook"; import Sort from "../sort"; +const SelectionContext = createContext<{ + selection: Notebook[]; + enabled: boolean; + setEnabled: (value: boolean) => void; + toggleSelection: (item: Notebook) => void; +}>({ + selection: [], + enabled: false, + setEnabled: (_value: boolean) => {}, + toggleSelection: (_item: Notebook) => {} +}); +const useSelection = () => useContext(SelectionContext); + +type NotebookParentProp = { + parent?: NotebookParentProp; + item?: Notebook; +}; + type ConfigItem = { id: string; type: string }; class NotebookSheetConfig { static storageKey: "$$sp"; @@ -88,8 +106,10 @@ const useNotebookExpandedStore = create<{ export const NotebookSheet = () => { const [collapsed, setCollapsed] = useState(false); - const currentScreen = useNavigationStore((state) => state.currentScreen); - const canShow = currentScreen.name === "Notebook"; + const currentRoute = useNavigationStore((state) => state.currentRoute); + const focusedRouteId = useNavigationStore((state) => state.focusedRouteId); + + const canShow = currentRoute === "Notebook"; const [selection, setSelection] = useState<Notebook[]>([]); const [enabled, setEnabled] = useState(false); const { colors } = useThemeColors("sheet"); @@ -103,7 +123,7 @@ export const NotebookSheet = () => { nestedNotebooks: notebooks, nestedNotebookNotesCount: totalNotes, groupOptions - } = useNotebook(currentScreen.name === "Notebook" ? root : undefined); + } = useNotebook(currentRoute === "Notebook" ? root : undefined); const PLACEHOLDER_DATA = { heading: "Notebooks", @@ -158,8 +178,8 @@ export const NotebookSheet = () => { useEffect(() => { if (canShow) { setTimeout(async () => { - const id = currentScreen?.id; - const nextRoot = await findRootNotebookId(id); + if (!focusedRouteId) return; + const nextRoot = await findRootNotebookId(focusedRouteId); setRoot(nextRoot); if (nextRoot !== currentItem.current) { setSelection([]); @@ -183,7 +203,7 @@ export const NotebookSheet = () => { setEnabled(false); ref.current?.hide(); } - }, [canShow, currentScreen?.id, currentScreen.name, onRequestUpdate]); + }, [canShow, currentRoute, onRequestUpdate, focusedRouteId]); return ( <ActionSheet @@ -206,7 +226,7 @@ export const NotebookSheet = () => { NotebookSheetConfig.set( { type: "notebook", - id: currentScreen.id as string + id: focusedRouteId as string }, index ); @@ -392,24 +412,6 @@ export const NotebookSheet = () => { ); }; -const SelectionContext = createContext<{ - selection: Notebook[]; - enabled: boolean; - setEnabled: (value: boolean) => void; - toggleSelection: (item: Notebook) => void; -}>({ - selection: [], - enabled: false, - setEnabled: (_value: boolean) => {}, - toggleSelection: (_item: Notebook) => {} -}); -const useSelection = () => useContext(SelectionContext); - -type NotebookParentProp = { - parent?: NotebookParentProp; - item?: Notebook; -}; - const NotebookItem = ({ id, totalNotes, @@ -430,12 +432,12 @@ const NotebookItem = ({ nestedNotebooks, notebook: item } = useNotebook(id, items); - const screen = useNavigationStore((state) => state.currentScreen); + const isFocused = useNavigationStore((state) => state.focusedRouteId === id); const { colors } = useThemeColors("sheet"); const selection = useSelection(); const isSelected = selection.selection.findIndex((selected) => selected.id === item?.id) > -1; - const isFocused = screen.id === id; + const { fontScale } = useWindowDimensions(); const expanded = useNotebookExpandedStore((state) => state.expanded[id]); diff --git a/apps/mobile/app/components/sheets/sort/index.js b/apps/mobile/app/components/sheets/sort/index.js index 7d2c9a371..a4e995c28 100644 --- a/apps/mobile/app/components/sheets/sort/index.js +++ b/apps/mobile/app/components/sheets/sort/index.js @@ -36,8 +36,9 @@ const Sort = ({ type, screen }) => { db.settings.getGroupOptions(screen === "Notes" ? "home" : type + "s") ); const updateGroupOptions = async (_groupOptions) => { - await db.settings.setGroupOptions(type, _groupOptions); - + const groupType = screen === "Notes" ? "home" : type + "s"; + console.log("updateGroupOptions for group", groupType, "in", screen); + await db.settings.setGroupOptions(groupType, _groupOptions); setGroupOptions(_groupOptions); setTimeout(() => { if (screen !== "TopicSheet") Navigation.queueRoutesForUpdate(screen); diff --git a/apps/mobile/app/components/side-menu/color-section.tsx b/apps/mobile/app/components/side-menu/color-section.tsx index b4f6ef2e2..1c96cda5d 100644 --- a/apps/mobile/app/components/side-menu/color-section.tsx +++ b/apps/mobile/app/components/side-menu/color-section.tsx @@ -66,7 +66,7 @@ const ColorItem = React.memo( const onHeaderStateChange = useCallback( (state: any) => { setTimeout(() => { - let id = state.currentScreen?.id; + let id = state.focusedRouteId; if (id === item.id) { setHeaderTextState({ id: state.currentScreen.id }); } else { diff --git a/apps/mobile/app/components/side-menu/menu-item.js b/apps/mobile/app/components/side-menu/menu-item.js index 2ddf25fd3..dc5bca3ac 100644 --- a/apps/mobile/app/components/side-menu/menu-item.js +++ b/apps/mobile/app/components/side-menu/menu-item.js @@ -34,10 +34,9 @@ export const MenuItem = React.memo( function MenuItem({ item, index, testID, rightBtn }) { const { colors } = useThemeColors(); const [headerTextState, setHeaderTextState] = useState( - useNavigationStore.getState().currentScreen + useNavigationStore.getState().focusedRouteId ); - const screenId = item.name.toLowerCase() + "_navigation"; - let isFocused = headerTextState?.id === screenId; + let isFocused = headerTextState?.id === item.name; const primaryColors = isFocused ? colors.selected : colors.primary; const _onPress = () => { @@ -59,9 +58,9 @@ export const MenuItem = React.memo( const onHeaderStateChange = useCallback( (state) => { setTimeout(() => { - let id = state.currentScreen?.id; - if (id === screenId) { - setHeaderTextState({ id: state.currentScreen.id }); + let id = state.focusedRouteId; + if (id === item.name) { + setHeaderTextState({ id: state.focusedRouteId }); } else { if (headerTextState !== null) { setHeaderTextState(null); @@ -69,7 +68,7 @@ export const MenuItem = React.memo( } }, 300); }, - [headerTextState, screenId] + [headerTextState, item.name] ); useEffect(() => { diff --git a/apps/mobile/app/components/side-menu/pinned-section.tsx b/apps/mobile/app/components/side-menu/pinned-section.tsx index 9b596bfb8..6b2df225f 100644 --- a/apps/mobile/app/components/side-menu/pinned-section.tsx +++ b/apps/mobile/app/components/side-menu/pinned-section.tsx @@ -17,19 +17,19 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -import React, { useEffect, useRef, useState } from "react"; +import { Notebook, Tag } from "@notesnook/core"; +import { useThemeColors } from "@notesnook/theme"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import { FlatList, View } from "react-native"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; +import { db } from "../../common/database"; import NotebookScreen from "../../screens/notebook"; import { TaggedNotes } from "../../screens/notes/tagged"; -import { TopicNotes } from "../../screens/notes/topic-notes"; import Navigation from "../../services/navigation"; import { useMenuStore } from "../../stores/use-menu-store"; import useNavigationStore from "../../stores/use-navigation-store"; import { useNoteStore } from "../../stores/use-notes-store"; -import { useThemeColors } from "@notesnook/theme"; -import { db } from "../../common/database"; -import { normalize, SIZE } from "../../utils/size"; +import { SIZE, normalize } from "../../utils/size"; import { Properties } from "../properties"; import { Button } from "../ui/button"; import { Notice } from "../ui/notice"; @@ -38,8 +38,6 @@ import Seperator from "../ui/seperator"; import SheetWrapper from "../ui/sheet"; import Heading from "../ui/typography/heading"; import Paragraph from "../ui/typography/paragraph"; -import { useCallback } from "react"; -import { Notebook, Tag } from "@notesnook/core"; export const TagsSection = React.memo( function TagsSection() { @@ -127,7 +125,7 @@ export const PinItem = React.memo( const onHeaderStateChange = useCallback( (state: any) => { setTimeout(() => { - const id = state.currentScreen?.id; + const id = state.focusedRouteId; if (id === item.id) { setHeaderTextState({ id diff --git a/apps/mobile/app/hooks/use-actions.tsx b/apps/mobile/app/hooks/use-actions.tsx index 403f8698b..5439b5d9b 100644 --- a/apps/mobile/app/hooks/use-actions.tsx +++ b/apps/mobile/app/hooks/use-actions.tsx @@ -452,7 +452,7 @@ export const useActions = ({ } async function showAttachments() { - AttachmentDialog.present(item); + AttachmentDialog.present(item as Note); } async function exportNote() { @@ -496,12 +496,10 @@ export const useActions = ({ }; async function removeNoteFromNotebook() { - const currentScreen = useNavigationStore.getState().currentScreen; - if (currentScreen.name !== "Notebook") return; - await db.relations.unlink( - { type: "notebook", id: currentScreen.id }, - item - ); + const { currentRoute, focusedRouteId } = useNavigationStore.getState(); + if (currentRoute !== "Notebook" || !focusedRouteId) return; + + await db.relations.unlink({ type: "notebook", id: focusedRouteId }, item); Navigation.queueRoutesForUpdate(); close(); } @@ -509,7 +507,7 @@ export const useActions = ({ function addTo() { clearSelection(); setSelectedItem(item); - MoveNoteSheet.present(item); + MoveNoteSheet.present(item as Note); } async function addToFavorites() { @@ -867,11 +865,13 @@ export const useActions = ({ } useEffect(() => { - const currentScreen = useNavigationStore.getState().currentScreen; - if (item.type !== "note" || currentScreen.name !== "Notebook") return; + const { currentRoute, focusedRouteId } = useNavigationStore.getState(); + if (item.type !== "note" || currentRoute !== "Notebook" || !focusedRouteId) + return; + !!db.relations .to(item, "notebook") - .selector.find((v) => v("id", "==", currentScreen.id)) + .selector.find((v) => v("id", "==", focusedRouteId)) .then((notebook) => { setNoteInCurrentNotebook(!!notebook); }); diff --git a/apps/mobile/app/hooks/use-db-item.ts b/apps/mobile/app/hooks/use-db-item.ts index 676cf9400..58c63c094 100644 --- a/apps/mobile/app/hooks/use-db-item.ts +++ b/apps/mobile/app/hooks/use-db-item.ts @@ -56,9 +56,12 @@ export const useDBItem = <T extends keyof ItemTypeKey>( const onUpdateItem = (itemId?: string) => { if (typeof itemId === "string" && itemId !== id) return; if (!id) { - setItem(undefined); + if (item) { + setItem(undefined); + } return; } + console.log("onUpdateItem", id, type); if (items) { items.item(id).then((item) => { @@ -82,7 +85,7 @@ export const useDBItem = <T extends keyof ItemTypeKey>( return () => { eUnSubscribeEvent(eDBItemUpdate, onUpdateItem); }; - }, [id, type]); + }, [id, type, items, item]); return [ item as ItemTypeKey[T], @@ -116,6 +119,7 @@ export const useTotalNotes = ( } setTotalNotesById(totalNotesById); }); + console.log("useTotalNotes.getTotalNotes"); }, [ids, type]); useEffect(() => { diff --git a/apps/mobile/app/hooks/use-navigation-focus.ts b/apps/mobile/app/hooks/use-navigation-focus.ts index 6dc482fd1..c346bc12f 100644 --- a/apps/mobile/app/hooks/use-navigation-focus.ts +++ b/apps/mobile/app/hooks/use-navigation-focus.ts @@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. import { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { RefObject, useCallback, useEffect, useRef, useState } from "react"; +import { useRoute } from "@react-navigation/core"; +import useNavigationStore, { RouteName } from "../stores/use-navigation-store"; type NavigationFocus = { onFocus?: (prev: RefObject<boolean>) => boolean; @@ -31,6 +33,7 @@ export const useNavigationFocus = ( navigation: NativeStackNavigationProp<Record<string, object | undefined>>, { onFocus, onBlur, delay, focusOnInit = true }: NavigationFocus ) => { + const route = useRoute(); const [isFocused, setFocused] = useState(focusOnInit); const prev = useRef(false); const isBlurred = useRef(false); @@ -39,6 +42,12 @@ export const useNavigationFocus = ( setTimeout( () => { const shouldFocus = onFocus ? onFocus(prev) : true; + + const routeName = route.name?.startsWith("Settings") + ? "Settings" + : route.name; + useNavigationStore.getState().update(routeName as RouteName); + if (shouldFocus) { setFocused(true); prev.current = true; diff --git a/apps/mobile/app/hooks/use-notebook.ts b/apps/mobile/app/hooks/use-notebook.ts index 4cc1a2757..b3166bcb9 100644 --- a/apps/mobile/app/hooks/use-notebook.ts +++ b/apps/mobile/app/hooks/use-notebook.ts @@ -39,17 +39,19 @@ export const useNotebook = ( const onRequestUpdate = React.useCallback(() => { if (!item || !id) { - console.log("unset notebook"); - setNotebooks(undefined); + if (notebooks) { + setNotebooks(undefined); + } return; } + console.log("useNotebook.onRequestUpdate", id); db.relations .from(item, "notebook") .selector.sorted(db.settings.getGroupOptions("notebooks")) .then((notebooks) => { setNotebooks(notebooks); }); - }, [item, id]); + }, [item, id, notebooks]); useEffect(() => { onRequestUpdate(); @@ -75,7 +77,7 @@ export const useNotebook = ( eUnSubscribeEvent("groupOptionsUpdate", onUpdate); eUnSubscribeEvent(eOnNotebookUpdated, onNotebookUpdate); }; - }, [onUpdate, onRequestUpdate, id]); + }, [onUpdate, onRequestUpdate, id, refresh]); return { notebook: item, diff --git a/apps/mobile/app/navigation/navigation-stack.js b/apps/mobile/app/navigation/navigation-stack.js index 8bef45a3c..9e0c6dc41 100644 --- a/apps/mobile/app/navigation/navigation-stack.js +++ b/apps/mobile/app/navigation/navigation-stack.js @@ -35,7 +35,6 @@ import Notebooks from "../screens/notebooks"; import { ColoredNotes } from "../screens/notes/colored"; import { Monographs } from "../screens/notes/monographs"; import { TaggedNotes } from "../screens/notes/tagged"; -import { TopicNotes } from "../screens/notes/topic-notes"; import Reminders from "../screens/reminders"; import { Search } from "../screens/search"; import Settings from "../screens/settings"; @@ -120,44 +119,14 @@ const _Tabs = () => { <NativeStack.Screen name="Welcome" component={IntroStackNavigator} /> <NativeStack.Screen name="Notes" component={Home} /> <NativeStack.Screen name="Notebooks" component={Notebooks} /> - <NativeStack.Screen - options={{ lazy: true }} - name="Favorites" - component={Favorites} - /> - <NativeStack.Screen - options={{ lazy: true }} - name="Trash" - component={Trash} - /> - <NativeStack.Screen - options={{ lazy: true }} - name="Tags" - component={Tags} - /> + <NativeStack.Screen name="Favorites" component={Favorites} /> + <NativeStack.Screen name="Trash" component={Trash} /> + <NativeStack.Screen name="Tags" component={Tags} /> <NativeStack.Screen name="Settings" component={Settings} /> + <NativeStack.Screen name="TaggedNotes" component={TaggedNotes} /> + <NativeStack.Screen name="ColoredNotes" component={ColoredNotes} /> + <NativeStack.Screen name="Reminders" component={Reminders} /> <NativeStack.Screen - options={{ lazy: true }} - name="TaggedNotes" - component={TaggedNotes} - /> - <NativeStack.Screen - options={{ lazy: true }} - name="TopicNotes" - component={TopicNotes} - /> - <NativeStack.Screen - options={{ lazy: true }} - name="ColoredNotes" - component={ColoredNotes} - /> - <NativeStack.Screen - options={{ lazy: true }} - name="Reminders" - component={Reminders} - /> - <NativeStack.Screen - options={{ lazy: true }} name="Monographs" initialParams={{ item: { type: "monograph" }, @@ -166,16 +135,8 @@ const _Tabs = () => { }} component={Monographs} /> - <NativeStack.Screen - options={{ lazy: true }} - name="Notebook" - component={NotebookScreen} - /> - <NativeStack.Screen - options={{ lazy: true }} - name="Search" - component={Search} - /> + <NativeStack.Screen name="Notebook" component={NotebookScreen} /> + <NativeStack.Screen name="Search" component={Search} /> </NativeStack.Navigator> ); }; diff --git a/apps/mobile/app/screens/favorites/index.tsx b/apps/mobile/app/screens/favorites/index.tsx index 3dbbc2a3e..742fdfd29 100644 --- a/apps/mobile/app/screens/favorites/index.tsx +++ b/apps/mobile/app/screens/favorites/index.tsx @@ -28,6 +28,7 @@ import SettingsService from "../../services/settings"; import { useFavoriteStore } from "../../stores/use-favorite-store"; import useNavigationStore from "../../stores/use-navigation-store"; import { useNoteStore } from "../../stores/use-notes-store"; +import { Header } from "../../components/header"; const prepareSearch = () => { SearchService.update({ placeholder: "Search in favorites", @@ -50,9 +51,7 @@ export const Favorites = ({ route.name, Navigation.routeUpdateFunctions[route.name] ); - useNavigationStore.getState().update({ - name: route.name - }); + useNavigationStore.getState().setFocusedRouteId(route?.name); SearchService.prepareSearch = prepareSearch; return !prev?.current; }, @@ -61,23 +60,43 @@ export const Favorites = ({ }); return ( - <DelayLayout wait={loading}> - <List - data={favorites} - dataType="note" - onRefresh={() => { - setFavorites(); + <> + <Header + renderedInRoute={route.name} + title={route.name} + canGoBack={false} + hasSearch={true} + id={route.name} + onSearch={() => { + Navigation.push("Search", { + placeholder: `Type a keyword to search in ${route.name?.toLowerCase()}`, + type: "note", + title: route.name, + route: route.name, + ids: favorites?.ids.filter( + (id) => typeof id === "string" + ) as string[] + }); }} - renderedInRoute="Favorites" - loading={loading || !isFocused} - placeholder={{ - title: "Your favorites", - paragraph: "You have not added any notes to favorites yet.", - loading: "Loading your favorites" - }} - headerTitle="Favorites" /> - </DelayLayout> + <DelayLayout wait={loading}> + <List + data={favorites} + dataType="note" + onRefresh={() => { + setFavorites(); + }} + renderedInRoute="Favorites" + loading={loading || !isFocused} + placeholder={{ + title: "Your favorites", + paragraph: "You have not added any notes to favorites yet.", + loading: "Loading your favorites" + }} + headerTitle="Favorites" + /> + </DelayLayout> + </> ); }; diff --git a/apps/mobile/app/screens/home/index.tsx b/apps/mobile/app/screens/home/index.tsx index a6c4e4c68..f95f4dbd9 100755 --- a/apps/mobile/app/screens/home/index.tsx +++ b/apps/mobile/app/screens/home/index.tsx @@ -18,26 +18,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ import React from "react"; -import { db } from "../../common/database"; import { FloatingButton } from "../../components/container/floating-button"; import DelayLayout from "../../components/delay-layout"; +import { Header } from "../../components/header"; import List from "../../components/list"; import { useNavigationFocus } from "../../hooks/use-navigation-focus"; import Navigation, { NavigationProps } from "../../services/navigation"; -import SearchService from "../../services/search"; import SettingsService from "../../services/settings"; -import useNavigationStore from "../../stores/use-navigation-store"; import { useNoteStore } from "../../stores/use-notes-store"; import { openEditor } from "../notes/common"; - -const prepareSearch = () => { - SearchService.update({ - placeholder: "Type a keyword to search in notes", - type: "notes", - title: "Notes", - get: () => db.notes?.all - }); -}; +import useNavigationStore from "../../stores/use-navigation-store"; export const Home = ({ navigation, route }: NavigationProps<"Notes">) => { const notes = useNoteStore((state) => state.notes); @@ -48,11 +38,7 @@ export const Home = ({ navigation, route }: NavigationProps<"Notes">) => { route.name, Navigation.routeUpdateFunctions[route.name] ); - useNavigationStore.getState().update({ - name: route.name - }); - SearchService.prepareSearch = prepareSearch; - useNavigationStore.getState().setButtonAction(openEditor); + useNavigationStore.getState().setFocusedRouteId(route.name); return !prev?.current; }, onBlur: () => false, @@ -60,23 +46,41 @@ export const Home = ({ navigation, route }: NavigationProps<"Notes">) => { }); return ( - <DelayLayout wait={loading} delay={500}> - <List - data={notes} - dataType="note" - renderedInRoute="Notes" - loading={loading || !isFocused} - headerTitle="Notes" - placeholder={{ - title: "Notes", - paragraph: "You have not added any notes yet.", - button: "Add your first note", - action: openEditor, - loading: "Loading your notes" + <> + <Header + renderedInRoute={route.name} + title={route.name} + canGoBack={false} + hasSearch={true} + onSearch={() => { + Navigation.push("Search", { + placeholder: `Type a keyword to search in ${route.name?.toLowerCase()}`, + type: "note", + title: route.name, + route: route.name + }); }} + id={route.name} + onPressDefaultRightButton={openEditor} /> - <FloatingButton title="Create a new note" onPress={openEditor} /> - </DelayLayout> + <DelayLayout wait={loading} delay={500}> + <List + data={notes} + dataType="note" + renderedInRoute={route.name} + loading={loading || !isFocused} + headerTitle={route.name} + placeholder={{ + title: route.name?.toLowerCase(), + paragraph: `You have not added any ${route.name.toLowerCase()} yet.`, + button: "Add your first note", + action: openEditor, + loading: "Loading your notes" + }} + /> + <FloatingButton title="Create a new note" onPress={openEditor} /> + </DelayLayout> + </> ); }; diff --git a/apps/mobile/app/screens/notebook/index.tsx b/apps/mobile/app/screens/notebook/index.tsx index a125b1299..367789ff5 100644 --- a/apps/mobile/app/screens/notebook/index.tsx +++ b/apps/mobile/app/screens/notebook/index.tsx @@ -21,6 +21,7 @@ import { Note, Notebook } from "@notesnook/core/dist/types"; import React, { useEffect, useRef, useState } from "react"; import { db } from "../../common/database"; import DelayLayout from "../../components/delay-layout"; +import { Header } from "../../components/header"; import List from "../../components/list"; import { NotebookHeader } from "../../components/list-items/headers/notebook-header"; import { AddNotebookSheet } from "../../components/sheets/add-notebook"; @@ -30,7 +31,6 @@ import { eUnSubscribeEvent } from "../../services/event-manager"; import Navigation, { NavigationProps } from "../../services/navigation"; -import SearchService from "../../services/search"; import useNavigationStore, { NotebookScreenParams } from "../../stores/use-navigation-store"; @@ -46,7 +46,6 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => { onFocus: () => { Navigation.routeNeedsUpdate(route.name, onRequestUpdate); syncWithNavigation(); - useNavigationStore.getState().setButtonAction(openEditor); return false; }, onBlur: () => { @@ -56,21 +55,12 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => { }); const syncWithNavigation = React.useCallback(() => { - useNavigationStore.getState().update( - { - name: route.name, - title: params.current?.title, - id: params.current?.item?.id, - type: "notebook" - }, - params.current?.canGoBack - ); + useNavigationStore.getState().setFocusedRouteId(params?.current?.item?.id); setOnFirstSave({ type: "notebook", id: params.current.item.id }); - SearchService.prepareSearch = prepareSearch; - }, [route.name]); + }, []); const onRequestUpdate = React.useCallback( async (data?: NotebookScreenParams) => { @@ -111,44 +101,25 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => { }; }, []); - const prepareSearch = () => { - // SearchService.update({ - // placeholder: `Search in "${params.current.title}"`, - // type: "notes", - // title: params.current.title, - // get: () => { - // const notebook = db.notebooks?.notebook( - // params?.current?.item?.id - // )?.data; - // if (!notebook) return []; - // const notes = db.relations?.from(notebook, "note") || []; - // const topicNotes = db.notebooks - // .notebook(notebook.id) - // ?.topics.all.map((topic: Topic) => { - // return db.notes?.topicReferences - // .get(topic.id) - // .map((id: string) => db.notes?.note(id)?.data); - // }) - // .flat() - // .filter( - // (topicNote) => - // notes.findIndex((note) => note?.id !== topicNote?.id) === -1 - // ) as Note[]; - // return [...notes, ...topicNotes]; - // } - // }); - }; - - const PLACEHOLDER_DATA = { - title: params.current.item?.title, - paragraph: "You have not added any notes yet.", - button: "Add your first note", - action: openEditor, - loading: "Loading notebook notes" - }; - return ( <> + <Header + renderedInRoute={route.name} + title={params.current.item?.title} + canGoBack={params?.current?.canGoBack} + hasSearch={true} + onSearch={() => { + Navigation.push("Search", { + placeholder: `Type a keyword to search in ${params.current.item?.title}`, + type: "note", + title: params.current.item?.title, + route: route.name, + ids: notes?.ids.filter((id) => typeof id === "string") as string[] + }); + }} + id={params.current.item?.id} + onPressDefaultRightButton={openEditor} + /> <DelayLayout> <List data={notes} @@ -170,7 +141,13 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => { } /> } - placeholder={PLACEHOLDER_DATA} + placeholder={{ + title: params.current.item?.title, + paragraph: "You have not added any notes yet.", + button: "Add your first note", + action: openEditor, + loading: "Loading notebook notes" + }} /> </DelayLayout> </> @@ -179,19 +156,11 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => { NotebookScreen.navigate = (item: Notebook, canGoBack?: boolean) => { if (!item) return; - Navigation.navigate<"Notebook">( - { - title: item.title, - name: "Notebook", - id: item.id, - type: "notebook" - }, - { - title: item.title, - item: item, - canGoBack - } - ); + Navigation.navigate<"Notebook">("Notebook", { + title: item.title, + item: item, + canGoBack + }); }; export default NotebookScreen; diff --git a/apps/mobile/app/screens/notebooks/index.tsx b/apps/mobile/app/screens/notebooks/index.tsx index 130cf70ba..69527f3ae 100644 --- a/apps/mobile/app/screens/notebooks/index.tsx +++ b/apps/mobile/app/screens/notebooks/index.tsx @@ -19,32 +19,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. import React, { useEffect } from "react"; import { Config } from "react-native-config"; -import { db } from "../../common/database"; import { FloatingButton } from "../../components/container/floating-button"; import DelayLayout from "../../components/delay-layout"; +import { Header } from "../../components/header"; import List from "../../components/list"; import { AddNotebookSheet } from "../../components/sheets/add-notebook"; import { Walkthrough } from "../../components/walkthroughs"; import { useNavigationFocus } from "../../hooks/use-navigation-focus"; import Navigation, { NavigationProps } from "../../services/navigation"; -import SearchService from "../../services/search"; import SettingsService from "../../services/settings"; import useNavigationStore from "../../stores/use-navigation-store"; import { useNotebookStore } from "../../stores/use-notebook-store"; -const onPressFloatingButton = () => { +const onButtonPress = () => { AddNotebookSheet.present(); }; -const prepareSearch = () => { - SearchService.update({ - placeholder: "Type a keyword to search in notebooks", - type: "notebooks", - title: "Notebooks", - get: () => db.notebooks?.all - }); -}; - export const Notebooks = ({ navigation, route @@ -56,12 +46,7 @@ export const Notebooks = ({ route.name, Navigation.routeUpdateFunctions[route.name] ); - useNavigationStore.getState().update({ - name: route.name - }); - SearchService.prepareSearch = prepareSearch; - useNavigationStore.getState().setButtonAction(onPressFloatingButton); - + useNavigationStore.getState().setFocusedRouteId(route.name); return !prev?.current; }, onBlur: () => false, @@ -79,29 +64,47 @@ export const Notebooks = ({ }, [notebooks]); return ( - <DelayLayout delay={1}> - <List - data={notebooks} - dataType="notebook" - renderedInRoute="Notebooks" - loading={!isFocused} - placeholder={{ - title: "Your notebooks", - paragraph: "You have not added any notebooks yet.", - button: "Add your first notebook", - action: onPressFloatingButton, - loading: "Loading your notebooks" + <> + <Header + renderedInRoute={route.name} + title={route.name} + canGoBack={route.params?.canGoBack} + hasSearch={true} + id={route.name} + onSearch={() => { + Navigation.push("Search", { + placeholder: `Type a keyword to search in ${route.name?.toLowerCase()}`, + type: "notebook", + title: route.name, + route: route.name + }); }} - headerTitle="Notebooks" + onPressDefaultRightButton={onButtonPress} /> - - {!notebooks || notebooks.ids.length === 0 || !isFocused ? null : ( - <FloatingButton - title="Create a new notebook" - onPress={onPressFloatingButton} + <DelayLayout delay={1}> + <List + data={notebooks} + dataType="notebook" + renderedInRoute="Notebooks" + loading={!isFocused} + placeholder={{ + title: "Your notebooks", + paragraph: "You have not added any notebooks yet.", + button: "Add your first notebook", + action: onButtonPress, + loading: "Loading your notebooks" + }} + headerTitle="Notebooks" /> - )} - </DelayLayout> + + {!notebooks || notebooks.ids.length === 0 || !isFocused ? null : ( + <FloatingButton + title="Create a new notebook" + onPress={onButtonPress} + /> + )} + </DelayLayout> + </> ); }; diff --git a/apps/mobile/app/screens/notes/colored.tsx b/apps/mobile/app/screens/notes/colored.tsx index 68ca469b5..9a11d297d 100644 --- a/apps/mobile/app/screens/notes/colored.tsx +++ b/apps/mobile/app/screens/notes/colored.tsx @@ -18,13 +18,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ import { Color } from "@notesnook/core/dist/types"; -import { groupArray } from "@notesnook/core/dist/utils/grouping"; import React from "react"; -import NotesPage, { PLACEHOLDER_DATA } from "."; +import NotesPage from "."; import { db } from "../../common/database"; import Navigation, { NavigationProps } from "../../services/navigation"; import { NotesScreenParams } from "../../stores/use-navigation-store"; -import { openEditor, toCamelCase } from "./common"; +import { PLACEHOLDER_DATA, openEditor, toCamelCase } from "./common"; export const ColoredNotes = ({ navigation, route @@ -54,18 +53,9 @@ ColoredNotes.get = async (params: NotesScreenParams, grouped = true) => { ColoredNotes.navigate = (item: Color, canGoBack: boolean) => { if (!item) return; - Navigation.navigate<"ColoredNotes">( - { - name: "ColoredNotes", - title: toCamelCase(item.title), - id: item.id, - type: "color", - color: item.title?.toLowerCase() - }, - { - item: item, - canGoBack, - title: toCamelCase(item.title) - } - ); + Navigation.navigate<"ColoredNotes">("ColoredNotes", { + item: item, + canGoBack, + title: toCamelCase(item.title) + }); }; diff --git a/apps/mobile/app/screens/notes/common.ts b/apps/mobile/app/screens/notes/common.ts index 327ddde88..0293a6596 100644 --- a/apps/mobile/app/screens/notes/common.ts +++ b/apps/mobile/app/screens/notes/common.ts @@ -29,6 +29,14 @@ import { openLinkInBrowser } from "../../utils/functions"; import { tabBarRef } from "../../utils/global-refs"; import { editorController, editorState } from "../editor/tiptap/utils"; +export const PLACEHOLDER_DATA = { + title: "Your notes", + paragraph: "You have not added any notes yet.", + button: "Add your first Note", + action: openEditor, + loading: "Loading your notes." +}; + export function toCamelCase(title: string) { if (!title) return ""; return title.slice(0, 1).toUpperCase() + title.slice(1); diff --git a/apps/mobile/app/screens/notes/index.tsx b/apps/mobile/app/screens/notes/index.tsx index 502cd1e52..5e4022abe 100644 --- a/apps/mobile/app/screens/notes/index.tsx +++ b/apps/mobile/app/screens/notes/index.tsx @@ -17,21 +17,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -import { - Color, - GroupedItems, - Item, - Note, - Topic -} from "@notesnook/core/dist/types"; +import { VirtualizedGrouping } from "@notesnook/core"; +import { Color, Note } from "@notesnook/core/dist/types"; import React, { useEffect, useRef, useState } from "react"; -import { View } from "react-native"; -import { db } from "../../common/database"; import { FloatingButton } from "../../components/container/floating-button"; import DelayLayout from "../../components/delay-layout"; +import { Header } from "../../components/header"; import List from "../../components/list"; -import { IconButton } from "../../components/ui/icon-button"; -import Paragraph from "../../components/ui/typography/paragraph"; +import { PlaceholderData } from "../../components/list/empty"; import { useNavigationFocus } from "../../hooks/use-navigation-focus"; import { eSubscribeEvent, @@ -45,39 +38,11 @@ import useNavigationStore, { RouteName } from "../../stores/use-navigation-store"; import { useNoteStore } from "../../stores/use-notes-store"; -import { SIZE } from "../../utils/size"; - -import NotebookScreen from "../notebook/index"; -import { - openEditor, - openMonographsWebpage, - setOnFirstSave, - toCamelCase -} from "./common"; -import { PlaceholderData } from "../../components/list/empty"; -import { VirtualizedGrouping } from "@notesnook/core"; +import { setOnFirstSave } from "./common"; export const WARNING_DATA = { title: "Some notes in this topic are not synced" }; -export const PLACEHOLDER_DATA = { - title: "Your notes", - paragraph: "You have not added any notes yet.", - button: "Add your first Note", - action: openEditor, - loading: "Loading your notes." -}; - -export const MONOGRAPH_PLACEHOLDER_DATA = { - heading: "Your monographs", - paragraph: "You have not published any notes as monographs yet.", - button: "Learn more about monographs", - action: openMonographsWebpage, - loading: "Loading published notes.", - type: "monographs", - buttonIcon: "information-outline" -}; - export interface RouteProps<T extends RouteName> extends NavigationProps<T> { get: ( params: NotesScreenParams, @@ -93,7 +58,6 @@ export interface RouteProps<T extends RouteName> extends NavigationProps<T> { function getItemType(routeName: RouteName) { if (routeName === "TaggedNotes") return "tag"; if (routeName === "ColoredNotes") return "color"; - if (routeName === "TopicNotes") return "topic"; if (routeName === "Monographs") return "monograph"; return "note"; } @@ -110,24 +74,24 @@ const NotesPage = ({ "NotesPage" | "TaggedNotes" | "Monographs" | "ColoredNotes" | "TopicNotes" >) => { const params = useRef<NotesScreenParams>(route?.params); - const [notes, setNotes] = useState<VirtualizedGrouping<Note>>(); - const loading = useNoteStore((state) => state.loading); const [loadingNotes, setLoadingNotes] = useState(true); const isMonograph = route.name === "Monographs"; - - // const notebook = - // route.name === "TopicNotes" && - // params.current.item.type === "topic" && - // params.current.item.notebookId - // ? db.notebooks?.notebook((params.current.item as Topic).notebookId)?.data - // : null; + const title = + params.current?.item.type === "tag" + ? "#" + params.current?.item.title + : params.current?.item.title; + const accentColor = + route.name === "ColoredNotes" + ? (params.current?.item as Color)?.colorCode + : undefined; const isFocused = useNavigationFocus(navigation, { onFocus: (prev) => { Navigation.routeNeedsUpdate(route.name, onRequestUpdate); syncWithNavigation(); + if (focusControl) return !prev.current; return false; }, @@ -143,10 +107,7 @@ const NotesPage = ({ SearchService.update({ placeholder: `Search in ${item.title}`, type: "notes", - title: - item.type === "tag" - ? "#" + item.title - : toCamelCase((item as Color).title), + title: item.type === "tag" ? "#" + item.title : item.title, get: () => { return get(params.current, false); } @@ -154,31 +115,16 @@ const NotesPage = ({ }, [get]); const syncWithNavigation = React.useCallback(() => { - const { item, title } = params.current; - useNavigationStore.getState().update( - { - name: route.name, - title: - route.name === "ColoredNotes" ? toCamelCase(title as string) : title, - id: item?.id, - type: "notes", - notebookId: item.type === "topic" ? item.notebookId : undefined, - color: - item.type === "color" && route.name === "ColoredNotes" - ? item.title?.toLowerCase() - : undefined - }, - params.current.canGoBack, - rightButtons && rightButtons(params.current) - ); - SearchService.prepareSearch = prepareSearch; - useNavigationStore.getState().setButtonAction(onPressFloatingButton); + const { item } = params.current; + + useNavigationStore + .getState() + .setFocusedRouteId(params?.current?.item?.id || route.name); !isMonograph && setOnFirstSave({ type: getItemType(route.name), - id: item.id, - notebook: item.type === "topic" ? item.notebookId : undefined + id: item.id }); }, [ isMonograph, @@ -192,9 +138,6 @@ const NotesPage = ({ async (data?: NotesScreenParams) => { const isNew = data && data?.item?.id !== params.current?.item?.id; if (data) params.current = data; - params.current.title = - params.current.title || - (params.current.item as Item & { title: string }).title; const { item } = params.current; try { if (isNew) setLoadingNotes(true); @@ -204,9 +147,8 @@ const NotesPage = ({ )) as VirtualizedGrouping<Note>; if ( - ((item.type === "tag" || item.type === "color") && - (!notes || notes.ids.length === 0)) || - (item.type === "topic" && !notes) + (item.type === "tag" || item.type === "color") && + (!notes || notes.ids.length === 0) ) { return Navigation.goBack(); } @@ -243,81 +185,51 @@ const NotesPage = ({ }, [onRequestUpdate, route.name]); return ( - <DelayLayout - color={ - route.name === "ColoredNotes" - ? (params.current?.item as Color)?.colorCode - : undefined - } - wait={loading || loadingNotes} - > - {/* {route.name === "TopicNotes" ? ( - <View - style={{ - width: "100%", - paddingHorizontal: 12, - flexDirection: "row", - alignItems: "center" - }} - > - <Paragraph - onPress={() => { - Navigation.navigate({ - name: "Notebooks", - title: "Notebooks" - }); - }} - size={SIZE.xs} - > - Notebooks - </Paragraph> - {notebook ? ( - <> - <IconButton - name="chevron-right" - size={14} - customStyle={{ width: 25, height: 25 }} - /> - <Paragraph - onPress={() => { - NotebookScreen.navigate(notebook, true); - }} - size={SIZE.xs} - > - {notebook.title} - </Paragraph> - </> - ) : null} - </View> - ) : null} */} - <List - data={notes} - dataType="note" - onRefresh={onRequestUpdate} - loading={loading || !isFocused} - renderedInRoute="Notes" - headerTitle={params.current.title} - customAccentColor={ - route.name === "ColoredNotes" - ? (params.current?.item as Color)?.colorCode - : undefined + <> + <Header + renderedInRoute={route.name} + title={title} + canGoBack={params?.current?.canGoBack} + hasSearch={true} + id={ + route.name === "Monographs" ? "Monographs" : params?.current.item?.id } - placeholder={placeholder} + onSearch={() => { + Navigation.push("Search", { + placeholder: `Type a keyword to search in ${title}`, + type: "note", + title: title, + route: route.name, + ids: notes?.ids?.filter((id) => typeof id === "string") as string[] + }); + }} + accentColor={accentColor} + onPressDefaultRightButton={onPressFloatingButton} + headerRightButtons={rightButtons?.(params?.current)} /> - {!isMonograph && - ((notes?.ids && (notes?.ids?.length || 0) > 0) || isFocused) ? ( - <FloatingButton - color={ - route.name === "ColoredNotes" - ? (params.current?.item as Color)?.colorCode - : undefined - } - title="Create a note" - onPress={onPressFloatingButton} + <DelayLayout color={accentColor} wait={loading || loadingNotes}> + <List + data={notes} + dataType="note" + onRefresh={onRequestUpdate} + loading={loading || !isFocused} + renderedInRoute="Notes" + headerTitle={title} + customAccentColor={accentColor} + placeholder={placeholder} /> - ) : null} - </DelayLayout> + + {!isMonograph && + ((notes?.ids && (notes?.ids?.length || 0) > 0) || isFocused) ? ( + <FloatingButton + color={accentColor} + title="Create a note" + onPress={onPressFloatingButton} + /> + ) : null} + </DelayLayout> + </> ); }; diff --git a/apps/mobile/app/screens/notes/monographs.tsx b/apps/mobile/app/screens/notes/monographs.tsx index a7e61dcb6..6d3a88a77 100644 --- a/apps/mobile/app/screens/notes/monographs.tsx +++ b/apps/mobile/app/screens/notes/monographs.tsx @@ -18,12 +18,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ import React from "react"; -import NotesPage, { PLACEHOLDER_DATA } from "."; +import NotesPage from "."; import { db } from "../../common/database"; import Navigation, { NavigationProps } from "../../services/navigation"; import { NotesScreenParams } from "../../stores/use-navigation-store"; -import { MonographType } from "../../utils/types"; import { openMonographsWebpage } from "./common"; + +export const MONOGRAPH_PLACEHOLDER_DATA = { + title: "Your monographs", + paragraph: "You have not published any notes as monographs yet.", + button: "Learn more about monographs", + action: openMonographsWebpage, + loading: "Loading published notes.", + type: "monograph", + buttonIcon: "information-outline" +}; + export const Monographs = ({ navigation, route @@ -33,7 +43,7 @@ export const Monographs = ({ navigation={navigation} route={route} get={Monographs.get} - placeholder={PLACEHOLDER_DATA} + placeholder={MONOGRAPH_PLACEHOLDER_DATA} onPressFloatingButton={openMonographsWebpage} canGoBack={route.params?.canGoBack} focusControl={true} @@ -49,16 +59,10 @@ Monographs.get = async (params?: NotesScreenParams, grouped = true) => { return await db.monographs.all.grouped(db.settings.getGroupOptions("notes")); }; -Monographs.navigate = (item?: MonographType, canGoBack?: boolean) => { - Navigation.navigate<"Monographs">( - { - name: "Monographs", - type: "monograph" - }, - { - item: { type: "monograph" } as any, - canGoBack: canGoBack as boolean, - title: "Monographs" - } - ); +Monographs.navigate = (canGoBack?: boolean) => { + Navigation.navigate<"Monographs">("Monographs", { + item: { type: "monograph" } as any, + canGoBack: canGoBack as boolean, + title: "Monographs" + }); }; diff --git a/apps/mobile/app/screens/notes/tagged.tsx b/apps/mobile/app/screens/notes/tagged.tsx index 0bff3085f..ee754df71 100644 --- a/apps/mobile/app/screens/notes/tagged.tsx +++ b/apps/mobile/app/screens/notes/tagged.tsx @@ -19,11 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. import { Tag } from "@notesnook/core/dist/types"; import React from "react"; -import NotesPage, { PLACEHOLDER_DATA } from "."; +import NotesPage from "."; import { db } from "../../common/database"; import Navigation, { NavigationProps } from "../../services/navigation"; import { NotesScreenParams } from "../../stores/use-navigation-store"; -import { openEditor } from "./common"; +import { PLACEHOLDER_DATA, openEditor } from "./common"; + export const TaggedNotes = ({ navigation, route @@ -53,17 +54,9 @@ TaggedNotes.get = async (params: NotesScreenParams, grouped = true) => { TaggedNotes.navigate = (item: Tag, canGoBack?: boolean) => { if (!item) return; - Navigation.navigate<"TaggedNotes">( - { - name: "TaggedNotes", - title: item.title, - id: item.id, - type: "tag" - }, - { - item: item, - canGoBack, - title: item.title - } - ); + Navigation.navigate<"TaggedNotes">("TaggedNotes", { + item: item, + canGoBack, + title: item.title + }); }; diff --git a/apps/mobile/app/screens/notes/topic-notes.tsx b/apps/mobile/app/screens/notes/topic-notes.tsx deleted file mode 100644 index ca763f064..000000000 --- a/apps/mobile/app/screens/notes/topic-notes.tsx +++ /dev/null @@ -1,104 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -import { Topic } from "@notesnook/core/dist/types"; -import { groupArray } from "@notesnook/core/dist/utils/grouping"; -import React from "react"; -import NotesPage, { PLACEHOLDER_DATA } from "."; -import { db } from "../../common/database"; -import { MoveNotes } from "../../components/sheets/move-notes/movenote"; -import Navigation, { NavigationProps } from "../../services/navigation"; -import { NotesScreenParams } from "../../stores/use-navigation-store"; - -import { openEditor } from "./common"; - -const headerRightButtons = (params: NotesScreenParams) => [ - { - title: "Edit topic", - onPress: () => { - const { item } = params; - if (item.type !== "topic") return; - // eSendEvent(eOpenAddTopicDialog, { - // notebookId: item.notebookId, - // toEdit: item - // }); - } - }, - { - title: "Move notes", - onPress: () => { - const { item } = params; - if (item?.type !== "topic") return; - const notebook = db.notebooks?.notebook(item.notebookId); - if (notebook) { - MoveNotes.present(notebook.data, item); - } - } - } -]; - -export const TopicNotes = ({ - navigation, - route -}: NavigationProps<"TopicNotes">) => { - return ( - <> - <NotesPage - navigation={navigation} - route={route} - get={TopicNotes.get} - placeholderData={PLACEHOLDER_DATA} - onPressFloatingButton={openEditor} - rightButtons={headerRightButtons} - canGoBack={route.params?.canGoBack} - focusControl={true} - /> - </> - ); -}; - -TopicNotes.get = (params: NotesScreenParams, grouped = true) => { - const { id, notebookId } = params.item as Topic; - const topic = db.notebooks?.notebook(notebookId)?.topics.topic(id); - if (!topic) { - return []; - } - const notes = topic?.all || []; - return grouped - ? groupArray(notes, db.settings.getGroupOptions("notes")) - : notes; -}; - -TopicNotes.navigate = (item: Topic, canGoBack: boolean) => { - if (!item) return; - Navigation.navigate<"TopicNotes">( - { - name: "TopicNotes", - title: item.title, - id: item.id, - type: "topic", - notebookId: item.notebookId - }, - { - item: item, - canGoBack, - title: item.title - } - ); -}; diff --git a/apps/mobile/app/screens/reminders/index.tsx b/apps/mobile/app/screens/reminders/index.tsx index a57c1f3a9..4fa28b081 100644 --- a/apps/mobile/app/screens/reminders/index.tsx +++ b/apps/mobile/app/screens/reminders/index.tsx @@ -18,37 +18,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ import React from "react"; -import { db } from "../../common/database"; import { FloatingButton } from "../../components/container/floating-button"; import DelayLayout from "../../components/delay-layout"; +import { Header } from "../../components/header"; import List from "../../components/list"; import ReminderSheet from "../../components/sheets/reminder"; import { useNavigationFocus } from "../../hooks/use-navigation-focus"; import Navigation, { NavigationProps } from "../../services/navigation"; -import SearchService from "../../services/search"; import SettingsService from "../../services/settings"; import useNavigationStore from "../../stores/use-navigation-store"; import { useReminderStore } from "../../stores/use-reminder-store"; -const prepareSearch = () => { - SearchService.update({ - placeholder: "Search in reminders", - type: "reminders", - title: "Reminders", - get: () => db.reminders?.all - }); -}; - -const PLACEHOLDER_DATA = { - title: "Your reminders", - paragraph: "You have not set any reminders yet.", - button: "Set a new reminder", - action: () => { - ReminderSheet.present(); - }, - loading: "Loading reminders" -}; - export const Reminders = ({ navigation, route @@ -60,13 +40,8 @@ export const Reminders = ({ route.name, Navigation.routeUpdateFunctions[route.name] ); - useNavigationStore.getState().update({ - name: route.name, - beta: true - }); - SearchService.prepareSearch = prepareSearch; - useNavigationStore.getState().setButtonAction(PLACEHOLDER_DATA.action); + useNavigationStore.getState().setFocusedRouteId(route.name); return !prev?.current; }, onBlur: () => false, @@ -74,23 +49,52 @@ export const Reminders = ({ }); return ( - <DelayLayout> - <List - data={reminders} - dataType="reminder" - headerTitle="Reminders" - renderedInRoute="Reminders" - loading={!isFocused} - placeholder={PLACEHOLDER_DATA} - /> - - <FloatingButton - title="Set a new reminder" - onPress={() => { + <> + <Header + renderedInRoute={route.name} + title={route.name} + canGoBack={false} + hasSearch={true} + onSearch={() => { + Navigation.push("Search", { + placeholder: `Type a keyword to search in ${route.name}`, + type: "reminder", + title: route.name, + route: route.name + }); + }} + id={route.name} + onPressDefaultRightButton={() => { ReminderSheet.present(); }} /> - </DelayLayout> + + <DelayLayout> + <List + data={reminders} + dataType="reminder" + headerTitle="Reminders" + renderedInRoute="Reminders" + loading={!isFocused} + placeholder={{ + title: "Your reminders", + paragraph: "You have not set any reminders yet.", + button: "Set a new reminder", + action: () => { + ReminderSheet.present(); + }, + loading: "Loading reminders" + }} + /> + + <FloatingButton + title="Set a new reminder" + onPress={() => { + ReminderSheet.present(); + }} + /> + </DelayLayout> + </> ); }; diff --git a/apps/mobile/app/screens/search/index.js b/apps/mobile/app/screens/search/index.js deleted file mode 100644 index b26aea3e0..000000000 --- a/apps/mobile/app/screens/search/index.js +++ /dev/null @@ -1,78 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -import React, { useEffect } from "react"; -import DelayLayout from "../../components/delay-layout"; -import List from "../../components/list"; -import { useNavigationFocus } from "../../hooks/use-navigation-focus"; -import SearchService from "../../services/search"; -import useNavigationStore from "../../stores/use-navigation-store"; -import { useSearchStore } from "../../stores/use-search-store"; -import { inputRef } from "../../utils/global-refs"; -import { sleep } from "../../utils/time"; -export const Search = ({ navigation, route }) => { - const searchResults = useSearchStore((state) => state.searchResults); - const searching = useSearchStore((state) => state.searching); - const searchStatus = useSearchStore((state) => state.searchStatus); - const setSearchResults = useSearchStore((state) => state.setSearchResults); - const setSearchStatus = useSearchStore((state) => state.setSearchStatus); - - useNavigationFocus(navigation, { - onFocus: () => { - sleep(300).then(() => inputRef.current?.focus()); - useNavigationStore.getState().update({ - name: route.name - }); - return false; - }, - onBlur: () => false - }); - - useEffect(() => { - return () => { - setSearchResults([]); - setSearchStatus(false, null); - }; - }, [setSearchResults, setSearchStatus]); - - return ( - <DelayLayout wait={searching}> - <List - listData={searchResults} - type="search" - screen="Search" - focused={() => navigation.isFocused()} - placeholderText={"Notes you write appear here"} - jumpToDialog={true} - loading={searching} - CustomHeader={true} - placeholderData={{ - heading: "Search", - paragraph: - searchStatus || - `Type a keyword to search in ${ - SearchService.getSearchInformation().title - }`, - button: null, - loading: "Searching..." - }} - /> - </DelayLayout> - ); -}; diff --git a/apps/mobile/app/screens/search/index.tsx b/apps/mobile/app/screens/search/index.tsx new file mode 100644 index 000000000..83faeef3a --- /dev/null +++ b/apps/mobile/app/screens/search/index.tsx @@ -0,0 +1,84 @@ +/* +This file is part of the Notesnook project (https://notesnook.com/) + +Copyright (C) 2023 Streetwriters (Private) Limited + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +import { Item, VirtualizedGrouping } from "@notesnook/core"; +import React, { useState } from "react"; +import DelayLayout from "../../components/delay-layout"; +import List from "../../components/list"; +import { NavigationProps } from "../../services/navigation"; +import { SearchBar } from "./search-bar"; +import { db } from "../../common/database"; +export const Search = ({ route }: NavigationProps<"Search">) => { + const [results, setResults] = useState<VirtualizedGrouping<Item>>(); + const [loading, setLoading] = useState(false); + const [searchStatus, setSearchStatus] = useState<string>(); + + const onSearch = async (query: string) => { + if (!query) { + setResults(undefined); + setLoading(false); + setSearchStatus(undefined); + return; + } + try { + setLoading(true); + const type = + route.params.type === "trash" + ? "trash" + : ((route.params?.type + "s") as keyof typeof db.lookup); + console.log( + `Searching in ${type} for ${query}`, + route.params?.ids?.length + ); + const results = await db.lookup[type]( + query, + route.params?.type === "note" ? route.params?.ids : undefined + ); + console.log(`Found ${results.ids?.length} results for ${query}`); + setResults(results); + if (results.ids?.length === 0) { + setSearchStatus(`No results found for ${query}`); + } else { + setSearchStatus(undefined); + } + setLoading(false); + } catch (e) { + console.log(e); + } + }; + + return ( + <> + <SearchBar onChangeText={onSearch} loading={loading} /> + <List + data={results} + dataType={route.params?.type} + renderedInRoute={route.name} + loading={false} + placeholder={{ + title: route.name, + paragraph: + searchStatus || + `Type a keyword to search in ${route.params?.title}`, + loading: "Searching..." + }} + /> + </> + ); +}; diff --git a/apps/mobile/app/screens/search/search-bar.js b/apps/mobile/app/screens/search/search-bar.js deleted file mode 100644 index 066153cb7..000000000 --- a/apps/mobile/app/screens/search/search-bar.js +++ /dev/null @@ -1,148 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -import React, { useEffect, useRef, useState } from "react"; -import { View } from "react-native"; -import { TextInput } from "react-native-gesture-handler"; -import { IconButton } from "../../components/ui/icon-button"; -import { ToastManager } from "../../services/event-manager"; -import Navigation from "../../services/navigation"; -import SearchService from "../../services/search"; -import { useSearchStore } from "../../stores/use-search-store"; -import { useThemeColors } from "@notesnook/theme"; -import { SIZE } from "../../utils/size"; -import { sleep } from "../../utils/time"; -export const SearchBar = () => { - const { colors } = useThemeColors(); - const [value, setValue] = useState(null); - const inputRef = useRef(); - const setSearchResults = useSearchStore((state) => state.setSearchResults); - const setSearchStatus = useSearchStore((state) => state.setSearchStatus); - const searchingRef = useRef(0); - const onClear = () => { - //inputRef.current?.blur(); - inputRef.current?.clear(); - setValue(0); - SearchService.setTerm(null); - setSearchResults([]); - setSearchStatus(false, null); - }; - - useEffect(() => { - sleep(300).then(() => { - inputRef.current?.focus(); - }); - }, []); - - const onChangeText = (value) => { - setValue(value); - search(value); - }; - - const search = (value) => { - clearTimeout(searchingRef.current); - searchingRef.current = setTimeout(async () => { - try { - if (value === "" || !value) { - setSearchResults([]); - setSearchStatus(false, null); - return; - } - if (value?.length > 0) { - SearchService.setTerm(value); - await SearchService.search(); - } - } catch (e) { - console.log(e); - ToastManager.show({ - heading: "Error occured while searching", - message: e.message, - type: "error" - }); - } - }, 300); - }; - - return ( - <View - style={{ - height: 50, - flexDirection: "row", - alignItems: "center", - flexShrink: 1, - width: "100%" - }} - > - <IconButton - name="arrow-left" - size={SIZE.xl} - top={10} - bottom={10} - onPress={() => { - SearchService.setTerm(null); - Navigation.goBack(); - }} - color={colors.primary.paragraph} - type="gray" - customStyle={{ - paddingLeft: 0, - marginLeft: 0, - marginRight: 5 - }} - /> - - <TextInput - ref={inputRef} - testID="search-input" - style={{ - fontSize: SIZE.md + 1, - fontFamily: "OpenSans-Regular", - flexGrow: 1, - height: "100%", - color: colors.primary.paragraph - }} - onChangeText={onChangeText} - placeholder="Type a keyword" - textContentType="none" - returnKeyLabel="Search" - returnKeyType="search" - autoCapitalize="none" - autoCorrect={false} - placeholderTextColor={colors.primary.placeholder} - /> - - {value && value.length > 0 ? ( - <IconButton - name="close" - size={SIZE.md + 2} - top={20} - bottom={20} - right={20} - onPress={onClear} - type="grayBg" - color={colors.primary.icon} - customStyle={{ - width: 25, - height: 25 - }} - /> - ) : null} - </View> - ); -}; diff --git a/apps/mobile/app/screens/search/search-bar.tsx b/apps/mobile/app/screens/search/search-bar.tsx new file mode 100644 index 000000000..0243e4040 --- /dev/null +++ b/apps/mobile/app/screens/search/search-bar.tsx @@ -0,0 +1,94 @@ +/* +This file is part of the Notesnook project (https://notesnook.com/) + +Copyright (C) 2023 Streetwriters (Private) Limited + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +import { useThemeColors } from "@notesnook/theme"; +import React, { useRef } from "react"; +import { View } from "react-native"; +import { TextInput } from "react-native-gesture-handler"; +import { IconButton } from "../../components/ui/icon-button"; +import Navigation from "../../services/navigation"; +import { SIZE } from "../../utils/size"; +import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets"; +import { DDS } from "../../services/device-detection"; +export const SearchBar = ({ + onChangeText, + loading +}: { + onChangeText: (value: string) => void; + loading?: boolean; +}) => { + const insets = useGlobalSafeAreaInsets(); + const { colors } = useThemeColors(); + const inputRef = useRef<TextInput>(null); + const _onChangeText = (value: string) => { + onChangeText(value); + }; + + return ( + <View + style={{ + height: 50 + insets.top, + paddingTop: insets.top, + flexDirection: "row", + alignItems: "center", + flexShrink: 1, + width: "100%", + paddingHorizontal: 12 + }} + > + <IconButton + name="arrow-left" + size={SIZE.xxl} + top={10} + bottom={10} + onPress={() => { + Navigation.goBack(); + }} + color={colors.primary.paragraph} + type="gray" + customStyle={{ + paddingLeft: 0, + marginLeft: -5, + marginRight: DDS.isLargeTablet() ? 10 : 7 + }} + /> + + <TextInput + ref={inputRef} + testID="search-input" + style={{ + fontSize: SIZE.md + 1, + fontFamily: "OpenSans-Regular", + flexGrow: 1, + height: "100%", + color: colors.primary.paragraph + }} + autoFocus + onChangeText={_onChangeText} + placeholder="Type a keyword" + textContentType="none" + returnKeyLabel="Search" + returnKeyType="search" + autoCapitalize="none" + autoCorrect={false} + placeholderTextColor={colors.primary.placeholder} + /> + </View> + ); +}; diff --git a/apps/mobile/app/screens/settings/editor/state.ts b/apps/mobile/app/screens/settings/editor/state.ts index b1c5912c5..2de429f18 100644 --- a/apps/mobile/app/screens/settings/editor/state.ts +++ b/apps/mobile/app/screens/settings/editor/state.ts @@ -71,7 +71,7 @@ export const useDragState = create<DragState>( presets["custom"] = _data; db.settings.setToolbarConfig( - useSettingStore.getState().deviceMode || "mobile", + useSettingStore.getState().deviceMode || ("mobile" as any), { preset: "custom", config: clone(_data) @@ -81,7 +81,7 @@ export const useDragState = create<DragState>( }, setPreset: (preset) => { db.settings.setToolbarConfig( - useSettingStore.getState().deviceMode || "mobile", + useSettingStore.getState().deviceMode || ("mobile" as any), { preset, config: preset === "custom" ? clone(get().customPresetData) : [] @@ -99,7 +99,7 @@ export const useDragState = create<DragState>( const user = await db.user?.getUser(); if (!user) return; const toolbarConfig = db.settings.getToolbarConfig( - useSettingStore.getState().deviceMode || "mobile" + useSettingStore.getState().deviceMode || ("mobile" as any) ); if (!toolbarConfig) { logger.info("DragState", "No user defined toolbar config was found"); @@ -110,25 +110,20 @@ export const useDragState = create<DragState>( preset: preset, data: preset === "custom" - ? clone(toolbarConfig?.config) + ? clone(toolbarConfig?.config as any[]) : clone(presets[preset]), customPresetData: preset === "custom" - ? clone(toolbarConfig?.config) + ? clone(toolbarConfig?.config as any[]) : clone(presets["custom"]) }); } }), { name: "drag-state-storage", // unique name - getStorage: () => MMKV as StateStorage, + getStorage: () => MMKV as unknown as StateStorage, onRehydrateStorage: () => { return () => { - logger.info( - "DragState", - "rehydrated drag state", - useNoteStore.getState().loading - ); if (!useNoteStore.getState().loading) { useDragState.getState().init(); } else { diff --git a/apps/mobile/app/screens/settings/group.tsx b/apps/mobile/app/screens/settings/group.tsx index be613040e..b73fdb4eb 100644 --- a/apps/mobile/app/screens/settings/group.tsx +++ b/apps/mobile/app/screens/settings/group.tsx @@ -29,6 +29,7 @@ import { tabBarRef } from "../../utils/global-refs"; import { components } from "./components"; import { SectionItem } from "./section-item"; import { RouteParams, SettingSection } from "./types"; +import { Header } from "../../components/header"; const keyExtractor = (item: SettingSection) => item.id; const AnimatedKeyboardAvoidingFlatList = Animated.createAnimatedComponent( @@ -42,13 +43,7 @@ const Group = ({ useNavigationFocus(navigation, { onFocus: () => { tabBarRef.current?.lock(); - useNavigationStore.getState().update( - { - name: "SettingsGroup", - title: route.params.name as string - }, - true - ); + useNavigationStore.getState().setFocusedRouteId("Settings"); return false; } }); @@ -62,25 +57,33 @@ const Group = ({ ); return ( - <DelayLayout type="settings" delay={1}> - <View - style={{ - flex: 1 - }} - > - {route.params.sections ? ( - <AnimatedKeyboardAvoidingFlatList - entering={FadeInDown} - data={route.params.sections} - keyExtractor={keyExtractor} - renderItem={renderItem} - enableOnAndroid - enableAutomaticScroll - /> - ) : null} - {route.params.component ? components[route.params.component] : null} - </View> - </DelayLayout> + <> + <Header + renderedInRoute="Settings" + title={route.params.name as string} + canGoBack={true} + id="Settings" + /> + <DelayLayout type="settings" delay={1}> + <View + style={{ + flex: 1 + }} + > + {route.params.sections ? ( + <AnimatedKeyboardAvoidingFlatList + entering={FadeInDown} + data={route.params.sections} + keyExtractor={keyExtractor} + renderItem={renderItem} + enableOnAndroid + enableAutomaticScroll + /> + ) : null} + {route.params.component ? components[route.params.component] : null} + </View> + </DelayLayout> + </> ); }; diff --git a/apps/mobile/app/screens/settings/home.tsx b/apps/mobile/app/screens/settings/home.tsx index 098425c6f..511b6487c 100644 --- a/apps/mobile/app/screens/settings/home.tsx +++ b/apps/mobile/app/screens/settings/home.tsx @@ -38,6 +38,7 @@ import { SectionGroup } from "./section-group"; import { settingsGroups } from "./settings-data"; import { RouteParams, SettingSection } from "./types"; import SettingsUserSection from "./user-section"; +import { Header } from "../../components/header"; const keyExtractor = (item: SettingSection) => item.id; const Home = ({ @@ -48,9 +49,7 @@ const Home = ({ useNavigationFocus(navigation, { onFocus: () => { - useNavigationStore.getState().update({ - name: "Settings" - }); + useNavigationStore.getState().setFocusedRouteId("Settings"); return false; }, focusOnInit: true @@ -74,19 +73,17 @@ const Home = ({ }, []); return ( - <DelayLayout delay={300} type="settings"> - {loading && ( - //@ts-ignore // Migrate to typescript required. - <BaseDialog animated={false} bounce={false} visible={true}> - <View - style={{ - width: "100%", - height: "100%", - backgroundColor: colors.primary.background, - justifyContent: "center", - alignItems: "center" - }} - > + <> + <Header + renderedInRoute="Settings" + title="Settings" + canGoBack={false} + id="Settings" + /> + <DelayLayout delay={300} type="settings"> + {loading && ( + //@ts-ignore // Migrate to typescript required. + <BaseDialog animated={false} bounce={false} visible={true}> <View style={{ width: "100%", @@ -96,45 +93,55 @@ const Home = ({ alignItems: "center" }} > - <Heading color={colors.primary.paragraph} size={SIZE.lg}> - Logging out - </Heading> - <Paragraph color={colors.secondary.paragraph}> - Please wait while we log out and clear app data. - </Paragraph> <View style={{ - flexDirection: "row", - width: 100, - marginTop: 15 + width: "100%", + height: "100%", + backgroundColor: colors.primary.background, + justifyContent: "center", + alignItems: "center" }} > - <ProgressBarComponent - height={5} - width={100} - animated={true} - useNativeDriver - indeterminate - indeterminateAnimationDuration={2000} - unfilledColor={colors.secondary.background} - color={colors.primary.accent} - borderWidth={0} - /> + <Heading color={colors.primary.paragraph} size={SIZE.lg}> + Logging out + </Heading> + <Paragraph color={colors.secondary.paragraph}> + Please wait while we log out and clear app data. + </Paragraph> + <View + style={{ + flexDirection: "row", + width: 100, + marginTop: 15 + }} + > + <ProgressBarComponent + height={5} + width={100} + animated={true} + useNativeDriver + indeterminate + indeterminateAnimationDuration={2000} + unfilledColor={colors.secondary.background} + color={colors.primary.accent} + borderWidth={0} + /> + </View> </View> </View> - </View> - </BaseDialog> - )} + </BaseDialog> + )} - <Animated.FlatList - entering={FadeInDown} - data={settingsGroups} - windowSize={1} - keyExtractor={keyExtractor} - ListFooterComponent={<View style={{ height: 200 }} />} - renderItem={renderItem} - /> - </DelayLayout> + <Animated.FlatList + entering={FadeInDown} + data={settingsGroups} + windowSize={1} + keyExtractor={keyExtractor} + ListFooterComponent={<View style={{ height: 200 }} />} + renderItem={renderItem} + /> + </DelayLayout> + </> ); }; diff --git a/apps/mobile/app/screens/settings/index.tsx b/apps/mobile/app/screens/settings/index.tsx index debe48d24..c9d62393c 100644 --- a/apps/mobile/app/screens/settings/index.tsx +++ b/apps/mobile/app/screens/settings/index.tsx @@ -26,34 +26,6 @@ import Home from "./home"; import { RouteParams } from "./types"; const SettingsStack = createNativeStackNavigator<RouteParams>(); -// const Home = React.lazy(() => import(/* webpackChunkName: "settings-home" */ './home')); -// const Group = React.lazy(() => import(/* webpackChunkName: "settings-group" */ './group')); - -// const Fallback = () => { -// return ( -// <> -// <Header /> -// <DelayLayout wait={true} type="settings" /> -// </> -// ); -// }; - -// const HomeScreen = (props: NativeStackScreenProps<RouteParams, 'SettingsHome'>) => { -// return ( -// <React.Suspense fallback={<Fallback />}> -// <Home {...props} /> -// </React.Suspense> -// ); -// }; - -// const GroupScreen = (props: NativeStackScreenProps<RouteParams, 'SettingsGroup'>) => { -// return ( -// <React.Suspense fallback={<Fallback />}> -// <Group {...props} /> -// </React.Suspense> -// ); -// }; - export const Settings = () => { const { colors } = useThemeColors(); return ( @@ -62,7 +34,7 @@ export const Settings = () => { screenListeners={{ focus: (e) => { if (e.target?.startsWith("SettingsHome-")) { - useNavigationStore.getState().update({ name: "Settings" }, false); + useNavigationStore.getState().update("Settings"); } } }} diff --git a/apps/mobile/app/screens/tags/index.tsx b/apps/mobile/app/screens/tags/index.tsx index 9a55a0878..048777074 100644 --- a/apps/mobile/app/screens/tags/index.tsx +++ b/apps/mobile/app/screens/tags/index.tsx @@ -18,23 +18,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ import React from "react"; -import { db } from "../../common/database"; import DelayLayout from "../../components/delay-layout"; +import { Header } from "../../components/header"; import List from "../../components/list"; import { useNavigationFocus } from "../../hooks/use-navigation-focus"; import Navigation, { NavigationProps } from "../../services/navigation"; -import SearchService from "../../services/search"; import SettingsService from "../../services/settings"; import useNavigationStore from "../../stores/use-navigation-store"; import { useTagStore } from "../../stores/use-tag-store"; -const prepareSearch = () => { - SearchService.update({ - placeholder: "Search in tags", - type: "tags", - title: "Tags", - get: () => db.tags?.all - }); -}; +import { db } from "../../common/database"; export const Tags = ({ navigation, route }: NavigationProps<"Tags">) => { const tags = useTagStore((state) => state.tags); @@ -44,11 +36,7 @@ export const Tags = ({ navigation, route }: NavigationProps<"Tags">) => { route.name, Navigation.routeUpdateFunctions[route.name] ); - useNavigationStore.getState().update({ - name: route.name - }); - - SearchService.prepareSearch = prepareSearch; + useNavigationStore.getState().setFocusedRouteId(route.name); return !prev?.current; }, onBlur: () => false, @@ -56,20 +44,36 @@ export const Tags = ({ navigation, route }: NavigationProps<"Tags">) => { }); return ( - <DelayLayout> - <List - data={tags} - dataType="tag" - headerTitle="Tags" - loading={!isFocused} - renderedInRoute="Tags" - placeholder={{ - title: "Your tags", - paragraph: "You have not created any tags for your notes yet.", - loading: "Loading your tags." + <> + <Header + renderedInRoute={route.name} + title={route.name} + canGoBack={false} + hasSearch={true} + onSearch={() => { + Navigation.push("Search", { + placeholder: `Type a keyword to search in ${route.name}`, + type: "tag", + title: route.name, + route: route.name + }); }} /> - </DelayLayout> + <DelayLayout> + <List + data={tags} + dataType="tag" + headerTitle="Tags" + loading={!isFocused} + renderedInRoute="Tags" + placeholder={{ + title: "Your tags", + paragraph: "You have not created any tags for your notes yet.", + loading: "Loading your tags." + }} + /> + </DelayLayout> + </> ); }; diff --git a/apps/mobile/app/screens/trash/index.tsx b/apps/mobile/app/screens/trash/index.tsx index 7b5cf90b4..740f03b17 100644 --- a/apps/mobile/app/screens/trash/index.tsx +++ b/apps/mobile/app/screens/trash/index.tsx @@ -22,22 +22,14 @@ import { db } from "../../common/database"; import { FloatingButton } from "../../components/container/floating-button"; import DelayLayout from "../../components/delay-layout"; import { presentDialog } from "../../components/dialog/functions"; +import { Header } from "../../components/header"; import List from "../../components/list"; import { useNavigationFocus } from "../../hooks/use-navigation-focus"; import { ToastManager } from "../../services/event-manager"; import Navigation, { NavigationProps } from "../../services/navigation"; -import SearchService from "../../services/search"; import useNavigationStore from "../../stores/use-navigation-store"; import { useSelectionStore } from "../../stores/use-selection-store"; import { useTrashStore } from "../../stores/use-trash-store"; -const prepareSearch = () => { - SearchService.update({ - placeholder: "Search in trash", - type: "trash", - title: "Trash", - get: () => db.trash?.all - }); -}; const onPressFloatingButton = () => { presentDialog({ @@ -77,40 +69,53 @@ export const Trash = ({ navigation, route }: NavigationProps<"Trash">) => { route.name, Navigation.routeUpdateFunctions[route.name] ); - useNavigationStore.getState().update({ - name: route.name - }); + useNavigationStore.getState().setFocusedRouteId(route.name); if ( !useTrashStore.getState().trash || useTrashStore.getState().trash?.ids?.length === 0 ) { useTrashStore.getState().setTrash(); } - SearchService.prepareSearch = prepareSearch; return false; }, onBlur: () => false }); return ( - <DelayLayout> - <List - data={trash} - dataType="trash" - renderedInRoute="Trash" - loading={!isFocused} - placeholder={PLACEHOLDER_DATA(db.settings.getTrashCleanupInterval())} - headerTitle="Trash" + <> + <Header + renderedInRoute={route.name} + title={route.name} + canGoBack={false} + hasSearch={true} + onSearch={() => { + Navigation.push("Search", { + placeholder: `Type a keyword to search in ${route.name}`, + type: "trash", + title: route.name, + route: route.name + }); + }} /> - - {trash && trash?.ids?.length !== 0 ? ( - <FloatingButton - title="Clear all trash" - onPress={onPressFloatingButton} - alwaysVisible={true} + <DelayLayout> + <List + data={trash} + dataType="trash" + renderedInRoute="Trash" + loading={!isFocused} + placeholder={PLACEHOLDER_DATA(db.settings.getTrashCleanupInterval())} + headerTitle="Trash" /> - ) : null} - </DelayLayout> + + {trash && trash?.ids?.length !== 0 ? ( + <FloatingButton + title="Clear all trash" + onPress={onPressFloatingButton} + alwaysVisible={true} + /> + ) : null} + </DelayLayout> + </> ); }; diff --git a/apps/mobile/app/services/navigation.ts b/apps/mobile/app/services/navigation.ts index 359a5fbfc..9c7184fe0 100755 --- a/apps/mobile/app/services/navigation.ts +++ b/apps/mobile/app/services/navigation.ts @@ -21,7 +21,6 @@ import { StackActions } from "@react-navigation/native"; import { NativeStackScreenProps } from "@react-navigation/native-stack"; import { useFavoriteStore } from "../stores/use-favorite-store"; import useNavigationStore, { - CurrentScreen, GenericRouteParam, RouteName, RouteParams @@ -34,8 +33,8 @@ import { useTrashStore } from "../stores/use-trash-store"; import { eOnNewTopicAdded } from "../utils/events"; import { rootNavigatorRef, tabBarRef } from "../utils/global-refs"; import { eSendEvent } from "./event-manager"; -import SettingsService from "./settings"; import SearchService from "./search"; +import SettingsService from "./settings"; /** * Routes that should be updated on focus @@ -113,59 +112,35 @@ function queueRoutesForUpdate(...routesToUpdate: RouteName[]) { routesToUpdate?.length > 0 ? routesToUpdate : (Object.keys(routeNames) as (keyof RouteParams)[]); - const currentScreen = useNavigationStore.getState().currentScreen; - if (routes.indexOf(currentScreen.name) > -1) { - routeUpdateFunctions[currentScreen.name]?.(); - clearRouteFromQueue(currentScreen.name); + const currentRoute = useNavigationStore.getState().currentRoute; + if (routes.indexOf(currentRoute) > -1) { + routeUpdateFunctions[currentRoute]?.(); + clearRouteFromQueue(currentRoute); // Remove focused screen from queue - routes.splice(routes.indexOf(currentScreen.name), 1); + routes.splice(routes.indexOf(currentRoute), 1); } routesUpdateQueue = routesUpdateQueue.concat(routes); routesUpdateQueue = [...new Set(routesUpdateQueue)]; } -function navigate<T extends RouteName>( - screen: Omit<Partial<CurrentScreen>, "name"> & { - name: keyof RouteParams; - }, - params?: RouteParams[T] -) { - useNavigationStore - .getState() - .update(screen as CurrentScreen, !!params?.canGoBack); - if (screen.name === "Notebook") - routeUpdateFunctions["Notebook"](params || {}); - if (screen.name?.endsWith("Notes") && screen.name !== "Notes") - routeUpdateFunctions[screen.name]?.(params || {}); - //@ts-ignore Not sure how to fix this for now ignore it. - rootNavigatorRef.current?.navigate<RouteName>(screen.name, params); +function navigate<T extends RouteName>(screen: T, params?: RouteParams[T]) { + rootNavigatorRef.current?.navigate(screen as any, params); } function goBack() { rootNavigatorRef.current?.goBack(); } -function push<T extends RouteName>( - screen: CurrentScreen, - params: RouteParams[T] -) { - useNavigationStore.getState().update(screen, !!params?.canGoBack); - rootNavigatorRef.current?.dispatch(StackActions.push(screen.name, params)); +function push<T extends RouteName>(screen: T, params: RouteParams[T]) { + rootNavigatorRef.current?.dispatch(StackActions.push(screen as any, params)); } -function replace<T extends RouteName>( - screen: CurrentScreen, - params: RouteParams[T] -) { - useNavigationStore.getState().update(screen, !!params?.canGoBack); - rootNavigatorRef.current?.dispatch(StackActions.replace(screen.name, params)); +function replace<T extends RouteName>(screen: T, params: RouteParams[T]) { + rootNavigatorRef.current?.dispatch(StackActions.replace(screen, params)); } function popToTop() { rootNavigatorRef.current?.dispatch(StackActions.popToTop()); - useNavigationStore.getState().update({ - name: (SettingsService.get().homepage as RouteName) || "Notes" - }); } function openDrawer() { diff --git a/apps/mobile/app/stores/item-selection-store.ts b/apps/mobile/app/stores/item-selection-store.ts new file mode 100644 index 000000000..13b565392 --- /dev/null +++ b/apps/mobile/app/stores/item-selection-store.ts @@ -0,0 +1,71 @@ +/* +This file is part of the Notesnook project (https://notesnook.com/) + +Copyright (C) 2023 Streetwriters (Private) Limited + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +import { Item } from "@notesnook/core"; +import create, { State } from "zustand"; + +export type SelectionState = "intermediate" | "selected" | "deselected"; +export type ItemSelection = Record<string, SelectionState | undefined>; +export interface SelectionStore extends State { + selection: ItemSelection; + setSelection: (state: ItemSelection) => void; + multiSelect: boolean; + toggleMultiSelect: (multiSelect: boolean) => void; + initialState: ItemSelection; + canEnableMultiSelectMode: boolean; + markAs: (item: Item, state: SelectionState | undefined) => void; + reset: () => void; +} + +export function createItemSelectionStore(multiSelectMode = false) { + return create<SelectionStore>((set, get) => ({ + selection: {}, + setSelection: (state) => { + set({ + selection: state + }); + }, + reset: () => { + set({ + selection: { ...get().initialState } + }); + }, + canEnableMultiSelectMode: multiSelectMode, + initialState: {}, + markAs: (item, state) => { + set({ + selection: { + ...get().selection, + [item.id]: + state === "deselected" + ? get().initialState === undefined + ? undefined + : "deselected" + : state + } + }); + }, + multiSelect: false, + toggleMultiSelect: () => { + if (!get().canEnableMultiSelectMode) return; + set({ + multiSelect: !get().multiSelect + }); + } + })); +} diff --git a/apps/mobile/app/stores/use-navigation-store.ts b/apps/mobile/app/stores/use-navigation-store.ts index 5ff30c6ff..fa2b57635 100644 --- a/apps/mobile/app/stores/use-navigation-store.ts +++ b/apps/mobile/app/stores/use-navigation-store.ts @@ -19,17 +19,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. import { Color, + ItemType, Note, Notebook, Reminder, Tag, - Topic, TrashItem } from "@notesnook/core/dist/types"; import create, { State } from "zustand"; import { ColorValues } from "../utils/colors"; -export type GenericRouteParam = { [name: string]: unknown }; +export type GenericRouteParam = undefined; export type NotebookScreenParams = { item: Notebook; @@ -38,7 +38,7 @@ export type NotebookScreenParams = { }; export type NotesScreenParams = { - item: Note | Notebook | Topic | Tag | Color | TrashItem | Reminder; + item: Note | Notebook | Tag | Color | TrashItem | Reminder; title: string; canGoBack?: boolean; }; @@ -56,90 +56,64 @@ export type AuthParams = { export type RouteParams = { Notes: GenericRouteParam; - Notebooks: GenericRouteParam; + Notebooks: { + canGoBack?: boolean; + }; Notebook: NotebookScreenParams; NotesPage: NotesScreenParams; Tags: GenericRouteParam; Favorites: GenericRouteParam; Trash: GenericRouteParam; - Search: GenericRouteParam; + Search: { + placeholder: string; + type: ItemType; + title: string; + route: RouteName; + ids?: string[]; + }; Settings: GenericRouteParam; TaggedNotes: NotesScreenParams; ColoredNotes: NotesScreenParams; TopicNotes: NotesScreenParams; Monographs: NotesScreenParams; AppLock: AppLockRouteParams; - Auth: AuthParams; Reminders: GenericRouteParam; SettingsGroup: GenericRouteParam; }; export type RouteName = keyof RouteParams; -export type CurrentScreen = { - name: RouteName; - id: string; - title?: string; - type?: string; - color?: string | null; - notebookId?: string; - beta?: boolean; -}; - export type HeaderRightButton = { title: string; onPress: () => void; }; interface NavigationStore extends State { - currentScreen: CurrentScreen; - currentScreenRaw: Partial<CurrentScreen>; + currentRoute: RouteName; canGoBack?: boolean; - update: ( - currentScreen: Omit<Partial<CurrentScreen>, "name"> & { - name: keyof RouteParams; - }, - canGoBack?: boolean, - headerRightButtons?: HeaderRightButton[] - ) => void; + focusedRouteId?: string; + update: (currentScreen: RouteName) => void; headerRightButtons?: HeaderRightButton[]; buttonAction: () => void; setButtonAction: (buttonAction: () => void) => void; + setFocusedRouteId: (id?: string) => void; } const useNavigationStore = create<NavigationStore>((set, get) => ({ - currentScreen: { - name: "Notes", - id: "notes_navigation", - title: "Notes", - type: "notes" - }, - currentScreenRaw: { name: "Notes" }, - canGoBack: false, - update: (currentScreen, canGoBack, headerRightButtons) => { - const color = - ColorValues[ - currentScreen.color?.toLowerCase() as keyof typeof ColorValues - ]; - if ( - JSON.stringify(currentScreen) === JSON.stringify(get().currentScreenRaw) - ) - return; + focusedRouteId: "Notes", + setFocusedRouteId: (id) => { set({ - currentScreen: { - name: currentScreen.name, - id: - currentScreen.id || currentScreen.name.toLowerCase() + "_navigation", - title: currentScreen.title || currentScreen.name, - type: currentScreen.type, - color: color, - notebookId: currentScreen.notebookId, - beta: currentScreen.beta - }, - currentScreenRaw: currentScreen, - canGoBack, - headerRightButtons: headerRightButtons + focusedRouteId: id }); + console.log("CurrentRoute ID", id); + }, + currentRoute: "Notes", + canGoBack: false, + update: (currentScreen) => { + set({ + currentRoute: currentScreen + }); + console.log("CurrentRoute", currentScreen); }, headerRightButtons: [], buttonAction: () => null, diff --git a/apps/mobile/native/ios/extension.bundle/clipper.bundle.js b/apps/mobile/native/ios/extension.bundle/clipper.bundle.js index a8b3ecc49..7491db92f 100644 --- a/apps/mobile/native/ios/extension.bundle/clipper.bundle.js +++ b/apps/mobile/native/ios/extension.bundle/clipper.bundle.js @@ -1 +1 @@ -(()=>{var e={110:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.isSVGElement=t.cloneNode=void 0;const r=n(32),o=n(787),s=["altGlyph","altGlyphDef","altGlyphItem","animate","animateColor","animateMotion","animateTransform","circle","clipPath","color-profile","cursor","defs","desc","ellipse","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence","filter","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignObject","g","glyph","glyphRef","hkern","image","line","linearGradient","marker","mask","metadata","missing-glyph","mpath","path","pattern","polygon","polyline","radialGradient","rect","set","stop","svg","switch","symbol","text","textPath","title","tref","tspan","use","view","vkern"].map((e=>e.toLowerCase())),a=["script"].map((e=>e.toLowerCase()));function l(e){return!(!e||!e.tagName)&&s.includes(e.tagName.toLowerCase())}t.cloneNode=function e(t,n){return i(this,void 0,void 0,(function*(){const{root:c,filter:u}=n;if(!c&&u&&!u(t))return null;let d=yield function(e,t){try{if(e instanceof HTMLCanvasElement&&(null==t?void 0:t.images))return(0,r.createImage)(e.toDataURL(),null==t?void 0:t.fetchOptions);if(!(null==t?void 0:t.images)&&e instanceof HTMLImageElement)return null;if(!(null==t?void 0:t.styles)&&(e instanceof HTMLButtonElement||e instanceof HTMLFormElement||e instanceof HTMLSelectElement||e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement))return null;if(e.nodeType===Node.COMMENT_NODE)return null;if((n=e)&&n.tagName&&a.includes(n.tagName.toLowerCase()))return null;if(e.nodeType!==Node.TEXT_NODE&&!l(e)){const{display:t,width:n,height:i}=window.getComputedStyle(e);if("none"===t||"0px"===n&&"0px"===i)return null;if(function(e){return!(!e||!e.tagName)&&!s.includes(e.tagName.toLowerCase())&&e.tagName.includes("-")}(e)){const n=t.includes("inline"),i=document.createElement(n?"span":"div");for(const t of e.attributes)i.setAttribute(t.name,t.value);return i}}return e.cloneNode(!1)}catch(e){return console.error("Failed to clone element",e),null}var n}(t,n);if(!d)return null;d=yield function(t,n,r){return i(this,void 0,void 0,(function*(){const o=t.childNodes;return 0===o.length||(yield function(t,n,r){return i(this,void 0,void 0,(function*(){for(const i of n){const n=yield e(i,Object.assign(Object.assign({},r),{root:!1}));n&&t.appendChild(n)}}))}(n,o,r)),n}))}(t,d,n);const h=function(e,t,n){return t instanceof Element?(n.styles&&(function(e,t,n){const{getElementStyles:i}=n,r=i&&i(e);if(!r)return;var o,s;t.style.cssText=r.cssText,"body"===e.tagName.toLowerCase()&&(o=getComputedStyle(e),(s=t.style).font=o.font,s.fontFamily=o.fontFamily,s.fontFeatureSettings=o.fontFeatureSettings,s.fontKerning=o.fontKerning,s.fontSize=o.fontSize,s.fontStretch=o.fontStretch,s.fontStyle=o.fontStyle,s.fontVariant=o.fontVariant,s.fontVariantCaps=o.fontVariantCaps,s.fontVariantEastAsian=o.fontVariantEastAsian,s.fontVariantLigatures=o.fontVariantLigatures,s.fontVariantNumeric=o.fontVariantNumeric,s.fontVariationSettings=o.fontVariationSettings,s.fontWeight=o.fontWeight);const a=t.getAttribute("style");a&&t.setAttribute("style",a.replace(/(:?[:;])(:? +)/gm,((e,t)=>t)))}(e,t,n),function(e,t,n){const{getPseudoElementStyles:i}=n;let r=!1;const s=document.createElement("style"),a=`pseudo--${(0,o.uid)()}`;for(const t of[":before",":after"]){const n=i&&i(e,t)||getComputedStyle(e,t);if(!n.cssText)continue;const o=`.${a}:${t} {\n ${n.cssText}\n }`;s.appendChild(document.createTextNode(o)),r=!0}r&&(t.className=a,t.appendChild(s))}(e,t,n)),function(e){const t=["href","src"],n=window.location.href;for(const i of t){const t=e.getAttribute(i),r=(null==t?void 0:t.startsWith("http"))?void 0:t;if(r){const t=new URL(r,n).href;e.setAttribute(i,t)}}}(t),function(e,t){(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement)&&t.setAttribute("value",e.value)}(e,t),function(e){e instanceof SVGElement&&(e.setAttribute("xmlns","http://www.w3.org/2000/svg"),["width","height"].forEach((function(t){const n=e.getAttribute(t);n&&!e.style.getPropertyValue(t)&&e.style.setProperty(t,n)})))}(t),t):t}(t,d,n);return h}))},t.isSVGElement=l},136:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.tokenize=void 0;const n=String.fromCharCode;function i(e,t){return 0|e.charCodeAt(t)}function r(e,t){return t.push(e),e}let o=1,s=1,a=0,l=0,c=0,u="";function d(){return c=l<a?i(u,l++):0,s++,10===c&&(s=1,o++),c}function h(e,t){return function(e,t,n){return e.slice(t,n)}(u,e,t)}function f(e){switch(e){case 0:case 9:case 10:case 13:case 32:return 5;case 33:case 42:case 43:case 44:case 47:case 62:case 64:case 126:case 59:case 123:case 125:return 4;case 58:return 3;case 34:case 39:case 40:case 91:return 2;case 41:case 93:return 1}return 0}function g(e){return h(l-1,m(91===e?e+2:40===e?e+1:e)).trim()}function m(e){for(;d();)switch(c){case e:return l;case 34:case 39:34!==e&&39!==e&&m(c);break;case 40:41===e&&m(e);break;case 92:d()}return l}function p(e){for(;!f(i(u,l));)d();return h(e,l)}t.tokenize=function(e){return function(e){return u="",e}(function(e){for(;d();)switch(f(c)){case 0:r(p(l-1),e);break;case 2:r(g(c),e);break;default:r(n(c),e)}return e}(function(e){return o=s=1,a=function(e){return e.length}(u=e),l=0,[]}(e)))}},917:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.getInlinedNode=t.toSvg=t.toPng=t.toPixelData=t.toCanvas=t.toBlob=t.toJpeg=void 0;const r=n(110),o=n(32),s=n(663),a=n(261),l=n(787),c=n(69),u={inlineOptions:{}};function d(e,t){return i(this,void 0,void 0,(function*(){const{fonts:n,images:i,stylesheets:o,inlineImages:l}=t.inlineOptions||{};o&&(yield(0,c.inlineStylesheets)(t.fetchOptions));const u=getComputedStyle(document.documentElement),d=o?(0,c.cacheStylesheets)(u):void 0;let h=yield(0,r.cloneNode)(e,{styles:t.styles,filter:t.filter,root:!0,vector:!t.raster,fetchOptions:t.fetchOptions,getElementStyles:null==d?void 0:d.get,getPseudoElementStyles:null==d?void 0:d.getPseudo,images:i});if(h&&!(h instanceof Text))return n&&(h=yield function(e,t){return(0,s.resolveAll)(t).then((function(t){const n=document.createElement("style");return e.appendChild(n),n.appendChild(document.createTextNode(t)),e}))}(h,t.fetchOptions)),l&&(yield(0,a.inlineAllImages)(h,t.fetchOptions)),function(e){for(const t of e.querySelectorAll("*"))if(t instanceof HTMLElement&&!(0,r.isSVGElement)(t)){for(const e of Array.from(t.attributes))"class"===e.name&&t.className.includes("pseudo--")||g.includes(e.name)||t.removeAttribute(e.name);t instanceof HTMLAnchorElement&&(t.href=t.href.startsWith("http")?t.href:document.location.origin+t.href)}}(h),h}))}function h(e,t){return i(this,void 0,void 0,(function*(){t.inlineOptions=Object.assign({fonts:!0,images:!0,stylesheets:!0},t.inlineOptions);let n=yield d(e,t);if(n)return n=function(e,t){return t.backgroundColor&&(e.style.backgroundColor=t.backgroundColor),t.width&&(e.style.width=t.width+"px"),t.height&&(e.style.height=t.height+"px"),e}(n,t),function(e,t,n){e.setAttribute("xmlns","http://www.w3.org/1999/xhtml");return'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="'+t+'" height="'+n+'"><foreignObject x="0" y="0" width="100%" height="100%">'+(0,l.escapeXhtml)((new XMLSerializer).serializeToString(e))+"</foreignObject></svg>"}(n,t.width||(0,l.width)(e),t.height||(0,l.height)(e))}))}function f(e,t){return t=Object.assign(Object.assign({},u),t),h(e,t).then((e=>e?(0,o.createImage)(e,t.fetchOptions):null)).then((0,l.delay)(0)).then((function(n){const i="number"!=typeof t.scale?1:t.scale,r=function(e,t,n){const i=document.createElement("canvas");if(i.width=(n.width||(0,l.width)(e))*t,i.height=(n.height||(0,l.height)(e))*t,n.backgroundColor){const e=i.getContext("2d");if(!e)return null;e.fillStyle=n.backgroundColor,e.fillRect(0,0,i.width,i.height)}return i}(e,i,t),o=null==r?void 0:r.getContext("2d");return o?(o.imageSmoothingEnabled=!1,n&&(o.scale(i,i),o.drawImage(n,0,0)),r):null}))}t.getInlinedNode=d,t.toSvg=h,t.toPixelData=function(e,t){return(t=t||{}).raster=!0,f(e,t).then((function(t){var n;return null===(n=null==t?void 0:t.getContext("2d"))||void 0===n?void 0:n.getImageData(0,0,(0,l.width)(e),(0,l.height)(e)).data}))},t.toPng=function(e,t){return t.raster=!0,f(e,t).then((function(e){return null==e?void 0:e.toDataURL()}))},t.toJpeg=function(e,t){return t.raster=!0,f(e,t).then((function(e){return null==e?void 0:e.toDataURL("image/jpeg",t.quality||1)}))},t.toBlob=function(e,t){return t.raster=!0,f(e,t).then((e=>e&&(0,l.canvasToBlob)(e)))},t.toCanvas=function(e,t){return t.raster=!0,f(e,t)};const g=["src","href","title","style","srcset","sizes","width","height","target","rel"]},32:function(e,t){"use strict";var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};function i(e,t){if(!e.startsWith("http"))return e;if((null==t?void 0:t.noCache)&&(e+=(/\?/.test(e)?"&":"?")+Date.now()),(null==t?void 0:t.bypassCors)&&(null==t?void 0:t.corsHost)){if(e.startsWith(t.corsHost))return e;e=`${t.corsHost}/${e}`}return e}Object.defineProperty(t,"__esModule",{value:!0}),t.constructUrl=t.reloadImage=t.createImage=t.fetchResource=void 0,t.fetchResource=function(e,t){return n(this,void 0,void 0,(function*(){if(!e)return null;const n=yield fetch(i(e,t));if(!n.ok)return"";const r=yield n.blob(),o=new FileReader;return o.readAsDataURL(r),new Promise((e=>{o.addEventListener("loadend",(()=>{"string"==typeof o.result&&e(o.result)}))}))}))},t.createImage=function(e,t){return"data:,"===e?Promise.resolve(null):new Promise((function(n,r){const o=new Image;o.crossOrigin=(null==t?void 0:t.crossOrigin)||null,o.onload=function(){n(o)},o.onerror=r,o.src=i(e,t)}))},t.reloadImage=function(e,t){return t.corsHost&&e.currentSrc.startsWith(t.corsHost)?Promise.resolve(null):(t.noCache=!0,new Promise((function(n,r){e.crossOrigin=t.crossOrigin||null,e.onload=function(){n(e)},e.onerror=t=>{console.error("Failed to load image",e.currentSrc),r(t)},e.src=i(e.currentSrc,t)})))},t.constructUrl=i},663:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.resolveAll=void 0;const r=n(783);function o(e){return{resolve:function(t){const n=(e.parentStyleSheet||{}).href||void 0;return(0,r.inlineAll)(e.cssText,t,n)},src:function(){return e.style.getPropertyValue("src")}}}function s(e){return e.filter((function(e){return e.type===CSSRule.FONT_FACE_RULE})).filter((function(e){return(0,r.shouldProcess)(e.style.getPropertyValue("src"))}))}t.resolveAll=function(e){return i(this,void 0,void 0,(function*(){const t=s(function(e){const t=[];for(const n of e)try{const e=s(Array.from(n.cssRules));e.length>3&&t.push(e[0])}catch(e){e instanceof Error&&console.log("Error while reading CSS rules from "+n.href,e.toString())}return t}(document.styleSheets)).map(o),n=[];for(const i of t)n.push(yield i.resolve(e));return n.join("\n")}))}},261:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.inlineAllImages=void 0;const r=n(32),o=n(783),s=n(787);function a(e,t){return i(this,void 0,void 0,(function*(){if((0,s.isDataUrl)(e.currentSrc))return Promise.resolve(null);const n=yield(0,r.fetchResource)(e.currentSrc||e.src,t);return n?"data:,"===n?(e.removeAttribute("src"),e):new Promise((function(t,i){var r,o;"PICTURE"===(null===(r=e.parentElement)||void 0===r?void 0:r.tagName)&&(null===(o=e.parentElement)||void 0===o||o.replaceWith(e)),e.onload=()=>t(e),e.onerror=e=>i(e),e.src=n,e.removeAttribute("srcset")})):null}))}function l(e,t){return i(this,void 0,void 0,(function*(){const n=e.style.getPropertyValue("background-image");if(!n)return e;const i=yield(0,o.inlineAll)(n,t);return e.style.setProperty("background-image",i),e}))}t.inlineAllImages=function(e,t){return i(this,void 0,void 0,(function*(){const n=e.querySelectorAll("img"),i=[];for(let e=0;e<n.length;++e){const r=n[e];i.push(a(r,t))}const r=e.querySelectorAll('[style*="background-image:"],[style*="background:"]');for(let e=0;e<r.length;++e){const n=r[e];i.push(l(n,t))}yield Promise.all(i).catch((e=>console.error(e)))}))}},590:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.enterNodeSelectionMode=t.clipScreenshot=t.cleanup=t.clipArticle=t.clipPage=void 0;const r=n(107),o=n(787),s=n(482),a=n(917),l={nodeHover:"nn-node-selection--hover",nodeSelected:"nn-node-selection--selected",nodeSelectionContainer:"nn-node-selection-container"},c=[l.nodeSelected,l.nodeSelectionContainer],u={fonts:!1,images:!0,stylesheets:!0};function d(e){for(const t of c)if(e.classList.contains(t)||e.closest(`.${t}`))return!1;return!0}t.clipPage=function(e,t,n){return i(this,void 0,void 0,(function*(){const{body:i,head:r}=yield v(e,n,t);return i&&r?`<!doctype html>\n${p(r,i).documentElement.outerHTML}`:null}))},t.clipArticle=function(e,t){return i(this,void 0,void 0,(function*(){const{body:n,head:i}=yield v(e,t);if(!n||!i)return null;const o=p(i,n),s=new r.Readability(o);s.PRESENTATIONAL_ATTRIBUTES=["align","background","bgcolor","border","cellpadding","cellspacing","frame","hspace","rules","valign","vspace"];const a=s.parse();return`<!DOCTYPE html><html>${(null==i?void 0:i.outerHTML)||""}<body>${(null==a?void 0:a.content)||""}</body></html>`}))},t.clipScreenshot=function(e,t="jpeg",n){return i(this,void 0,void 0,(function*(){const i=e||document.body,r="jpeg"===t?a.toJpeg:"png"===t?a.toPng:a.toBlob,o=yield r(i,{quality:1,backgroundColor:"white",width:document.body.scrollWidth,height:document.body.scrollHeight,fetchOptions:b(n),inlineOptions:{fonts:!0,images:!0,stylesheets:!0},styles:!0});return"jpeg"===t||"png"===t?`<img width="${document.body.scrollWidth}px" height="${document.body.scrollHeight}px" src="${o}" />`:o}))};const h=e=>{const t=e.target;!t.classList.contains(l.nodeHover)&&d(t)&&t.classList.add(l.nodeHover)},f=e=>{const t=e.target;t.classList.contains(l.nodeHover)&&t.classList.remove(l.nodeHover)},g=e=>{e.preventDefault();const t=e.target;t.classList.contains(l.nodeSelected)?t.classList.remove(l.nodeSelected):d(t)&&t.classList.add(l.nodeSelected)};function m(e){e.nodeType!==Node.TEXT_NODE&&e.getBoundingClientRect||!e.parentElement||(e=e.parentElement);const t=function(e){const t={isInViewport:!1,isPartiallyInViewport:!1,isInsideViewport:!1,isAroundViewport:!1,isOnEdge:!1,isOnTopEdge:!1,isOnRightEdge:!1,isOnBottomEdge:!1,isOnLeftEdge:!1},n=e.getBoundingClientRect(),i=window.innerHeight||document.documentElement.clientHeight,r=window.innerWidth||document.documentElement.clientWidth,o=n.left>=0&&n.left+n.width<=r,s=n.top>=0&&n.top+n.height<=i;t.isInsideViewport=o&&s;const a=n.left<0&&n.left+n.width>r,l=n.top<0&&n.top+n.height>i;t.isAroundViewport=a&&l;const c=n.top<0&&n.top+n.height>0,u=n.left<r&&n.left+n.width>r,d=n.left<0&&n.left+n.width>0,h=n.top<i&&n.top+n.height>i,f=s||l||c||h,g=o||a||d||u;t.isOnTopEdge=c&&g,t.isOnRightEdge=u&&f,t.isOnBottomEdge=h&&g,t.isOnLeftEdge=d&&f,t.isOnEdge=t.isOnLeftEdge||t.isOnRightEdge||t.isOnTopEdge||t.isOnBottomEdge;const m=o||a||t.isOnLeftEdge||t.isOnRightEdge,p=s||l||t.isOnTopEdge||t.isOnBottomEdge;return t.isInViewport=m&&p,t.isPartiallyInViewport=t.isInViewport&&t.isOnEdge,t}(e);return t.isInViewport}function p(e,t){const n=document.implementation.createHTMLDocument();return n.documentElement.replaceChildren(e,t),n}function y(){setTimeout((()=>{var e;document.querySelectorAll(`.${l.nodeSelected}`).forEach((e=>{e instanceof HTMLElement&&e.classList.remove(l.nodeSelected)})),document.querySelectorAll(`.${l.nodeSelectionContainer}`).forEach((e=>e.remove())),(e=document).body.removeEventListener("mouseout",f),e.body.removeEventListener("mouseover",h),document.body.removeEventListener("click",g)}),0)}function v(e,t,n=!1){return i(this,void 0,void 0,(function*(){const i=yield(0,a.getInlinedNode)(e.body,{raster:!0,fetchOptions:b(t),inlineOptions:{fonts:!1,inlineImages:null==t?void 0:t.inlineImages,images:null==t?void 0:t.images,stylesheets:null==t?void 0:t.styles},styles:null==t?void 0:t.styles,filter:e=>!n||m(e)});if(!i)return{};const r=e.createElement("head"),o=e.createElement("title");return o.innerText=e.title,r.appendChild(o),{body:i,head:r}}))}function b(e){return(null==e?void 0:e.corsProxy)?{bypassCors:!0,corsHost:e.corsProxy,crossOrigin:"anonymous",noCache:!0}:void 0}t.enterNodeSelectionMode=function(e,t){return setTimeout((()=>{!function(e){e.body.addEventListener("click",g)}(e),function(e){e.body.addEventListener("mouseout",f),e.body.addEventListener("mouseover",h)}(e)}),0),function(){const e=`.${l.nodeHover} {\n border: 1px solid green;\n background-color: rgb(0,0,0,0.05);\n cursor: pointer;\n }\n\n .${l.nodeSelected} {\n border: 2px solid green;\n cursor: pointer;\n }\n\n .${l.nodeSelectionContainer} {\n position: fixed;\n bottom: 0px;\n right: 0px;\n z-index: ${Number.MAX_VALUE};\n }`;(0,o.injectCss)(e,"nn-clipper-styles")}(),new Promise(((e,n)=>{!function(e,t){const n=document.createElement("div");n.classList.add(l.nodeSelectionContainer),setTimeout((()=>{document.body.appendChild(n)}),0),(0,s.app)({init:{isClipping:!1},view:({isClipping:n})=>(0,s.h)("div",{style:{padding:"10px",backgroundColor:"white",borderRadius:"5px",boxShadow:"0px 0px 10px 0px #00000038"}},[(0,s.h)("p",{style:{marginBottom:"0px",fontSize:"18px"}},[(0,s.text)("Notesnook Web Clipper")]),(0,s.h)("p",{style:{margin:"0px",marginBottom:"5px",fontStyle:"italic"}},[n?(0,s.text)("Clipping selected elements. Please wait..."):(0,s.text)("Click on any element to select it.")]),(0,s.h)("div",{style:{display:"flex",alignItems:"center"}},[(0,s.h)("button",{onclick:t=>[Object.assign(Object.assign({},t),{isClipping:!0}),t=>{null==e||e(),t({isClipping:!1})}],style:{marginRight:"5px"},disabled:n},[n?(0,s.text)("Clipping..."):(0,s.text)("Clip")]),(0,s.h)("button",{onclick:e=>(y(),null==t||t(),e),disabled:n},[(0,s.text)("Cancel")])])]),node:n})}((()=>i(this,void 0,void 0,(function*(){y();const n=document.querySelectorAll(`.${l.nodeSelected}`),i=document.createElement("div");for(const e of n){e.classList.remove(l.nodeSelected);const n=yield(0,a.getInlinedNode)(e,{raster:!1,fetchOptions:b(t),inlineOptions:u});n&&i.appendChild(n)}e(null==i?void 0:i.outerHTML)}))),(()=>n("Cancelled.")))}))},t.cleanup=y},783:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.readUrls=t.inlineAll=t.shouldProcess=void 0;const r=n(32),o=n(787),s=/url\(['"]?([^'"]+?)['"]?\)/g;function a(e){return-1!==e.search(s)}function l(e){const t=[];let n;for(;null!==(n=s.exec(e));)t.push(n[1]);return t.filter((function(e){return!(0,o.isDataUrl)(e)}))}function c(e,t,n,s){return i(this,void 0,void 0,(function*(){t=s?(0,o.resolveUrl)(t,s):t;const i=yield(0,r.fetchResource)(t,n);return e.replace((a=t,new RegExp("(url\\(['\"]?)("+(0,o.escape)(a)+")(['\"]?\\))","g")),"$1"+i+"$3");var a}))}t.shouldProcess=a,t.readUrls=l,t.inlineAll=function(e,t,n){return i(this,void 0,void 0,(function*(){if(!a(e))return e;const i=l(e);let r=e;for(const e of i)r=yield c(r,e,t,n);return r}))}},69:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.cacheStylesheets=t.inlineStylesheets=void 0;const r=n(32),o=n(302),s=n(136),a=n(763),l=["animation","background","border","border-block-end","border-block-start","border-bottom","border-color","border-image","border-inline-end","border-inline-start","border-left","border-radius","border-right","border-style","border-top","border-width","column-rule","columns","contain-intrinsic-size","flex","flex-flow","font","gap","grid","grid-area","grid-column","grid-row","grid-template","grid-gap","list-style","margin","mask","offset","outline","overflow","padding","place-content","place-items","place-self","scroll-margin","scroll-padding","text-decoration","text-emphasis","transition"];function c(e,t){return i(this,void 0,void 0,(function*(){try{const n=document.createElement("style"),i=yield fetch((0,r.constructUrl)(e,t));return!!i.ok&&(n.innerText=yield i.text(),n.setAttribute("href",e),n)}catch(t){console.error("Failed to inline stylesheet",e,t)}}))}function u(e,t,n,i,r){for(const a of e)if(a instanceof CSSStyleRule){if((s=a.selectorText).includes(":before")||s.includes(":after")||s.includes("::after")||s.includes("::before")){const e=p(a.selectorText);for(const t of e){if(!t||!t.selector.trim())continue;const e=document.querySelectorAll(t.selector);for(const n of e){if(!(n instanceof HTMLElement||n instanceof SVGElement))continue;const e=i.get(n)||[];i.set(n,e),e.push({rule:a.style,href:m(r),pseudoElement:t.pseudoElement})}}}const e=document.querySelectorAll(a.selectorText);for(const t of e){if(!(t instanceof HTMLElement||t instanceof SVGElement))continue;const e=a.selectorText.split(","),i=n.get(t)||[];n.set(t,i);for(const t of e)try{const e=(0,o.calculate)(t)[0];i.push({specificity:e.specificityArray,rule:a.style,href:m(r)});break}catch(e){console.error(e,r&&m(r))}}}else(a instanceof CSSMediaRule&&window.matchMedia(a.conditionText).matches||a instanceof CSSSupportsRule&&CSS.supports(a.conditionText))&&u(a.cssRules,t,n,i,r);var s}function d(e,t,n){const i=function(){const e=new CSSStyleSheet;return e.insertRule(".dummy{}"),e.cssRules[0].style}(),r=function(e){let t;return Object.defineProperty({},"style",{get:()=>(t||(t=getComputedStyle(e)),t)})}(e),o=["display"];for(const e of t)for(const t of[...e.rule,...l]){let s=e.rule.getPropertyValue(t);o.includes(t)&&(s=r.style.getPropertyValue(t)),s.trim()&&h(i,t,s,(e=>r.style.getPropertyValue(e)||n.getPropertyValue(e)),(t=>(console.log("resolving url",t,e.href),t.startsWith("data:")||!e.href?t:(console.log("resolving url",t,e.href.href),t.startsWith("/")?new URL(`${e.href.origin}${t}`).href:new URL(`${e.href.href}${t}`).href))),e.rule.getPropertyPriority(t))}return i}function h(e,t,n,i,r,o){n=function(e,t){const n=(0,s.tokenize)(e),i=[];for(let e=0;e<n.length;++e){const r=n[e];if("url"!==r||n[e+1].startsWith("(data"))i.push(r);else{const o=t(n[++e].slice(2,-2));o&&(i.push(r),i.push('("'),i.push(o),i.push('")'))}}return i.join("")}(n=g(n,i),r),e.setProperty(t,n,o)}function f(e){return e.media.mediaText.split(",").map((e=>e.trim())).includes("print")}function g(e,t){const n=(0,s.tokenize)(e),i=[];for(let e=0;e<n.length;++e){const r=n[e];if("var"===r){const r=(0,s.tokenize)(n[++e].slice(1,-1)),[o,a,l,...c]=r,u=t(o);u?i.push(u):a&&c.length<=1?i.push(c[0]||l):a&&2===c.length&&i.push(g(c.join(""),t))}else r.startsWith("(")&&r.endsWith(")")?i.push("(",g(r.slice(1,-1),t),")"):i.push(r)}return i.join("")}function m(e){if(!e)return null;e.startsWith("/")&&(e=`${document.location.origin}${e}`);const t=new URL(e),n=t.pathname.split("/").slice(0,-1).join("/");return new URL(`${t.origin}${n}/`)}function p(e){const t=[],n=(0,a.parse)(e);for(const e of n){const n=e.findIndex((e=>!(e.type!==a.SelectorType.Pseudo&&e.type!==a.SelectorType.PseudoElement||"after"!==e.name&&"before"!==e.name)));n<=-1||t.push({selector:(0,a.stringify)([e.slice(0,n)]),pseudoElement:(0,a.stringify)([e.slice(n)])})}return t}t.inlineStylesheets=function(e){return i(this,void 0,void 0,(function*(){for(const t of document.styleSheets){if(f(t))continue;const n=t.ownerNode;if(t.href&&n instanceof HTMLLinkElement)try{t.cssRules.length}catch(t){const i=yield c(n.href,e);i&&n.replaceWith(i),console.error("Failed to access sheet",n.href,t)}}yield function(e){return i(this,void 0,void 0,(function*(){let t=0;for(const n of document.styleSheets)if(!f(n))for(const i of n.cssRules){if(i.type===CSSRule.IMPORT_RULE){const r=i.href,o=yield c(r,e);o&&(n.ownerNode?n.ownerNode.before(o):document.head.appendChild(o),n.deleteRule(t))}++t}}))}(e)}))},t.cacheStylesheets=function(e){const t=new Map,n=new Map;for(const i of document.styleSheets){if(f(i))continue;let r=i.href||void 0;!r&&i.ownerNode instanceof HTMLElement&&(r=i.ownerNode.getAttribute("href")||void 0),u(i.cssRules,e,t,n,r)}return{getPseudo(t,i){var r;const o=null===(r=n.get(t))||void 0===r?void 0:r.filter((e=>e.pseudoElement.includes(i)));if(o&&o.length)return d(t,o,e)},get(n){const i=t.get(n);if(!i)return;const r=i.sort(((e,t)=>(0,o.compare)(e.specificity,t.specificity)));return r.push({rule:n.style,specificity:[0,0,0,0],href:null}),d(n,r,e)}}}},787:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.height=t.width=t.escapeXhtml=t.asArray=t.delay=t.uid=t.resolveUrl=t.canvasToBlob=t.isDataUrl=t.dataAsUrl=t.mimeType=t.parseExtension=t.escape=t.injectCss=void 0;const n="application/font-woff",i="image/jpeg",r={woff:n,woff2:n,ttf:"application/font-truetype",eot:"application/vnd.ms-fontobject",png:"image/png",jpg:i,jpeg:i,gif:"image/gif",tiff:"image/tiff",svg:"image/svg+xml"};function o(e){const t=/\.([^./]*?)(\?|$)/g.exec(e);return t?t[1]:""}t.parseExtension=o,t.mimeType=function(e){const t=o(e).toLowerCase();return r[t]||""},t.isDataUrl=function(e){return-1!==e.search(/^(data:)/)},t.canvasToBlob=function(e){return e.toBlob?new Promise((function(t){e.toBlob(t)})):Promise.resolve(function(e){const t=atob(e.toDataURL().split(",")[1]),n=t.length,i=new Uint8Array(n);for(let e=0;e<n;e++)i[e]=t.charCodeAt(e);return new Blob([i],{type:"image/png"})}(e))},t.resolveUrl=function(e,t){const n=document.implementation.createHTMLDocument(),i=n.createElement("base");n.head.appendChild(i);const r=n.createElement("a");return n.body.appendChild(r),i.href=t,r.href=e,r.href};let s=0;function a(e,t){const n=getComputedStyle(e).getPropertyValue(t);return parseFloat(n.replace("px",""))}t.uid=function(){return"u"+("0000"+(Math.random()*Math.pow(36,4)<<0).toString(36)).slice(-4)+s++},t.dataAsUrl=function(e,t){return"data:"+t+";base64,"+e},t.escape=function(e){return e.replace(/([.*+?^${}()|[\]/\\])/g,"\\$1")},t.delay=function(e){return function(t){return new Promise((function(n){setTimeout((function(){n(t)}),e)}))}},t.asArray=function(e){const t=[],n=e.length;for(let i=0;i<n;i++)t.push(e[i]);return t},t.escapeXhtml=function(e){return e.replace(/%/g,"%25").replace(/#/g,"%23").replace(/\n/g,"%0A")},t.width=function(e){const t=a(e,"border-left-width"),n=a(e,"border-right-width");return e.scrollWidth+t+n},t.height=function(e){const t=a(e,"border-top-width"),n=a(e,"border-bottom-width");return e.scrollHeight+t+n},t.injectCss=function(e,t){const n=document.getElementById(t),i=document.getElementsByTagName("head")[0];n&&i.removeChild(n);const r=document.createElement("style");r.type="text/css",r.id=t,r.appendChild(document.createTextNode(e)),i.insertBefore(r,function(){for(const e of document.querySelectorAll("style"))if(e.innerHTML.includes("#root"))return e;return null}())}},893:e=>{var t={unlikelyCandidates:/-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,okMaybeItsACandidate:/and|article|body|column|content|main|shadow/i};function n(e){return(!e.style||"none"!=e.style.display)&&!e.hasAttribute("hidden")&&(!e.hasAttribute("aria-hidden")||"true"!=e.getAttribute("aria-hidden")||e.className&&e.className.indexOf&&-1!==e.className.indexOf("fallback-image"))}e.exports=function(e,i={}){"function"==typeof i&&(i={visibilityChecker:i});var r={minScore:20,minContentLength:140,visibilityChecker:n};i=Object.assign(r,i);var o=e.querySelectorAll("p, pre, article"),s=e.querySelectorAll("div > br");if(s.length){var a=new Set(o);[].forEach.call(s,(function(e){a.add(e.parentNode)})),o=Array.from(a)}var l=0;return[].some.call(o,(function(e){if(!i.visibilityChecker(e))return!1;var n=e.className+" "+e.id;if(t.unlikelyCandidates.test(n)&&!t.okMaybeItsACandidate.test(n))return!1;if(e.matches("li p"))return!1;var r=e.textContent.trim().length;return!(r<i.minContentLength)&&(l+=Math.sqrt(r-i.minContentLength))>i.minScore}))}},174:e=>{function t(e,t){if(t&&t.documentElement)e=t,t=arguments[2];else if(!e||!e.documentElement)throw new Error("First argument to Readability constructor should be a document object.");if(t=t||{},this._doc=e,this._docJSDOMParser=this._doc.firstChild.__JSDOMParser__,this._articleTitle=null,this._articleByline=null,this._articleDir=null,this._articleSiteName=null,this._attempts=[],this._debug=!!t.debug,this._maxElemsToParse=t.maxElemsToParse||this.DEFAULT_MAX_ELEMS_TO_PARSE,this._nbTopCandidates=t.nbTopCandidates||this.DEFAULT_N_TOP_CANDIDATES,this._charThreshold=t.charThreshold||this.DEFAULT_CHAR_THRESHOLD,this._classesToPreserve=this.CLASSES_TO_PRESERVE.concat(t.classesToPreserve||[]),this._keepClasses=!!t.keepClasses,this._serializer=t.serializer||function(e){return e.innerHTML},this._disableJSONLD=!!t.disableJSONLD,this._flags=this.FLAG_STRIP_UNLIKELYS|this.FLAG_WEIGHT_CLASSES|this.FLAG_CLEAN_CONDITIONALLY,this._debug){let e=function(e){if(e.nodeType==e.TEXT_NODE)return`${e.nodeName} ("${e.textContent}")`;let t=Array.from(e.attributes||[],(function(e){return`${e.name}="${e.value}"`})).join(" ");return`<${e.localName} ${t}>`};this.log=function(){if("undefined"!=typeof dump){var t=Array.prototype.map.call(arguments,(function(t){return t&&t.nodeName?e(t):t})).join(" ");dump("Reader: (Readability) "+t+"\n")}else if("undefined"!=typeof console){let t=Array.from(arguments,(t=>t&&t.nodeType==this.ELEMENT_NODE?e(t):t));t.unshift("Reader: (Readability)"),console.log.apply(console,t)}}}else this.log=function(){}}t.prototype={FLAG_STRIP_UNLIKELYS:1,FLAG_WEIGHT_CLASSES:2,FLAG_CLEAN_CONDITIONALLY:4,ELEMENT_NODE:1,TEXT_NODE:3,DEFAULT_MAX_ELEMS_TO_PARSE:0,DEFAULT_N_TOP_CANDIDATES:5,DEFAULT_TAGS_TO_SCORE:"section,h2,h3,h4,h5,h6,p,td,pre".toUpperCase().split(","),DEFAULT_CHAR_THRESHOLD:500,REGEXPS:{unlikelyCandidates:/-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,okMaybeItsACandidate:/and|article|body|column|content|main|shadow/i,positive:/article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i,negative:/-ad-|hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,extraneous:/print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,byline:/byline|author|dateline|writtenby|p-author/i,replaceFonts:/<(\/?)font[^>]*>/gi,normalize:/\s{2,}/g,videos:/\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i,shareElements:/(\b|_)(share|sharedaddy)(\b|_)/i,nextLink:/(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i,prevLink:/(prev|earl|old|new|<|«)/i,tokenize:/\W+/g,whitespace:/^\s*$/,hasContent:/\S$/,hashUrl:/^#.+/,srcsetUrl:/(\S+)(\s+[\d.]+[xw])?(\s*(?:,|$))/g,b64DataUrl:/^data:\s*([^\s;,]+)\s*;\s*base64\s*,/i,jsonLdArticleTypes:/^Article|AdvertiserContentArticle|NewsArticle|AnalysisNewsArticle|AskPublicNewsArticle|BackgroundNewsArticle|OpinionNewsArticle|ReportageNewsArticle|ReviewNewsArticle|Report|SatiricalArticle|ScholarlyArticle|MedicalScholarlyArticle|SocialMediaPosting|BlogPosting|LiveBlogPosting|DiscussionForumPosting|TechArticle|APIReference$/},UNLIKELY_ROLES:["menu","menubar","complementary","navigation","alert","alertdialog","dialog"],DIV_TO_P_ELEMS:new Set(["BLOCKQUOTE","DL","DIV","IMG","OL","P","PRE","TABLE","UL"]),ALTER_TO_DIV_EXCEPTIONS:["DIV","ARTICLE","SECTION","P"],PRESENTATIONAL_ATTRIBUTES:["align","background","bgcolor","border","cellpadding","cellspacing","frame","hspace","rules","style","valign","vspace"],DEPRECATED_SIZE_ATTRIBUTE_ELEMS:["TABLE","TH","TD","HR","PRE"],PHRASING_ELEMS:["ABBR","AUDIO","B","BDO","BR","BUTTON","CITE","CODE","DATA","DATALIST","DFN","EM","EMBED","I","IMG","INPUT","KBD","LABEL","MARK","MATH","METER","NOSCRIPT","OBJECT","OUTPUT","PROGRESS","Q","RUBY","SAMP","SCRIPT","SELECT","SMALL","SPAN","STRONG","SUB","SUP","TEXTAREA","TIME","VAR","WBR"],CLASSES_TO_PRESERVE:["page"],HTML_ESCAPE_MAP:{lt:"<",gt:">",amp:"&",quot:'"',apos:"'"},_postProcessContent:function(e){this._fixRelativeUris(e),this._simplifyNestedElements(e),this._keepClasses||this._cleanClasses(e)},_removeNodes:function(e,t){if(this._docJSDOMParser&&e._isLiveNodeList)throw new Error("Do not pass live node lists to _removeNodes");for(var n=e.length-1;n>=0;n--){var i=e[n],r=i.parentNode;r&&(t&&!t.call(this,i,n,e)||r.removeChild(i))}},_replaceNodeTags:function(e,t){if(this._docJSDOMParser&&e._isLiveNodeList)throw new Error("Do not pass live node lists to _replaceNodeTags");for(const n of e)this._setNodeTag(n,t)},_forEachNode:function(e,t){Array.prototype.forEach.call(e,t,this)},_findNode:function(e,t){return Array.prototype.find.call(e,t,this)},_someNode:function(e,t){return Array.prototype.some.call(e,t,this)},_everyNode:function(e,t){return Array.prototype.every.call(e,t,this)},_concatNodeLists:function(){var e=Array.prototype.slice,t=e.call(arguments).map((function(t){return e.call(t)}));return Array.prototype.concat.apply([],t)},_getAllNodesWithTag:function(e,t){return e.querySelectorAll?e.querySelectorAll(t.join(",")):[].concat.apply([],t.map((function(t){var n=e.getElementsByTagName(t);return Array.isArray(n)?n:Array.from(n)})))},_cleanClasses:function(e){var t=this._classesToPreserve,n=(e.getAttribute("class")||"").split(/\s+/).filter((function(e){return-1!=t.indexOf(e)})).join(" ");for(n?e.setAttribute("class",n):e.removeAttribute("class"),e=e.firstElementChild;e;e=e.nextElementSibling)this._cleanClasses(e)},_fixRelativeUris:function(e){var t=this._doc.baseURI,n=this._doc.documentURI;function i(e){if(t==n&&"#"==e.charAt(0))return e;try{return new URL(e,t).href}catch(e){}return e}var r=this._getAllNodesWithTag(e,["a"]);this._forEachNode(r,(function(e){var t=e.getAttribute("href");if(t)if(0===t.indexOf("javascript:"))if(1===e.childNodes.length&&e.childNodes[0].nodeType===this.TEXT_NODE){var n=this._doc.createTextNode(e.textContent);e.parentNode.replaceChild(n,e)}else{for(var r=this._doc.createElement("span");e.firstChild;)r.appendChild(e.firstChild);e.parentNode.replaceChild(r,e)}else e.setAttribute("href",i(t))}));var o=this._getAllNodesWithTag(e,["img","picture","figure","video","audio","source"]);this._forEachNode(o,(function(e){var t=e.getAttribute("src"),n=e.getAttribute("poster"),r=e.getAttribute("srcset");if(t&&e.setAttribute("src",i(t)),n&&e.setAttribute("poster",i(n)),r){var o=r.replace(this.REGEXPS.srcsetUrl,(function(e,t,n,r){return i(t)+(n||"")+r}));e.setAttribute("srcset",o)}}))},_simplifyNestedElements:function(e){for(var t=e;t;){if(t.parentNode&&["DIV","SECTION"].includes(t.tagName)&&(!t.id||!t.id.startsWith("readability"))){if(this._isElementWithoutContent(t)){t=this._removeAndGetNext(t);continue}if(this._hasSingleTagInsideElement(t,"DIV")||this._hasSingleTagInsideElement(t,"SECTION")){for(var n=t.children[0],i=0;i<t.attributes.length;i++)n.setAttribute(t.attributes[i].name,t.attributes[i].value);t.parentNode.replaceChild(n,t),t=n;continue}}t=this._getNextNode(t)}},_getArticleTitle:function(){var e=this._doc,t="",n="";try{"string"!=typeof(t=n=e.title.trim())&&(t=n=this._getInnerText(e.getElementsByTagName("title")[0]))}catch(e){}var i=!1;function r(e){return e.split(/\s+/).length}if(/ [\|\-\\\/>»] /.test(t))i=/ [\\\/>»] /.test(t),r(t=n.replace(/(.*)[\|\-\\\/>»] .*/gi,"$1"))<3&&(t=n.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi,"$1"));else if(-1!==t.indexOf(": ")){var o=this._concatNodeLists(e.getElementsByTagName("h1"),e.getElementsByTagName("h2")),s=t.trim();this._someNode(o,(function(e){return e.textContent.trim()===s}))||(r(t=n.substring(n.lastIndexOf(":")+1))<3?t=n.substring(n.indexOf(":")+1):r(n.substr(0,n.indexOf(":")))>5&&(t=n))}else if(t.length>150||t.length<15){var a=e.getElementsByTagName("h1");1===a.length&&(t=this._getInnerText(a[0]))}var l=r(t=t.trim().replace(this.REGEXPS.normalize," "));return l<=4&&(!i||l!=r(n.replace(/[\|\-\\\/>»]+/g,""))-1)&&(t=n),t},_prepDocument:function(){var e=this._doc;this._removeNodes(this._getAllNodesWithTag(e,["style"])),e.body&&this._replaceBrs(e.body),this._replaceNodeTags(this._getAllNodesWithTag(e,["font"]),"SPAN")},_nextNode:function(e){for(var t=e;t&&t.nodeType!=this.ELEMENT_NODE&&this.REGEXPS.whitespace.test(t.textContent);)t=t.nextSibling;return t},_replaceBrs:function(e){this._forEachNode(this._getAllNodesWithTag(e,["br"]),(function(e){for(var t=e.nextSibling,n=!1;(t=this._nextNode(t))&&"BR"==t.tagName;){n=!0;var i=t.nextSibling;t.parentNode.removeChild(t),t=i}if(n){var r=this._doc.createElement("p");for(e.parentNode.replaceChild(r,e),t=r.nextSibling;t;){if("BR"==t.tagName){var o=this._nextNode(t.nextSibling);if(o&&"BR"==o.tagName)break}if(!this._isPhrasingContent(t))break;var s=t.nextSibling;r.appendChild(t),t=s}for(;r.lastChild&&this._isWhitespace(r.lastChild);)r.removeChild(r.lastChild);"P"===r.parentNode.tagName&&this._setNodeTag(r.parentNode,"DIV")}}))},_setNodeTag:function(e,t){if(this.log("_setNodeTag",e,t),this._docJSDOMParser)return e.localName=t.toLowerCase(),e.tagName=t.toUpperCase(),e;for(var n=e.ownerDocument.createElement(t);e.firstChild;)n.appendChild(e.firstChild);e.parentNode.replaceChild(n,e),e.readability&&(n.readability=e.readability);for(var i=0;i<e.attributes.length;i++)try{n.setAttribute(e.attributes[i].name,e.attributes[i].value)}catch(e){}return n},_prepArticle:function(e){this._cleanStyles(e),this._markDataTables(e),this._fixLazyImages(e),this._cleanConditionally(e,"form"),this._cleanConditionally(e,"fieldset"),this._clean(e,"object"),this._clean(e,"embed"),this._clean(e,"footer"),this._clean(e,"link"),this._clean(e,"aside");var t=this.DEFAULT_CHAR_THRESHOLD;this._forEachNode(e.children,(function(e){this._cleanMatchedNodes(e,(function(e,n){return this.REGEXPS.shareElements.test(n)&&e.textContent.length<t}))})),this._clean(e,"iframe"),this._clean(e,"input"),this._clean(e,"textarea"),this._clean(e,"select"),this._clean(e,"button"),this._cleanHeaders(e),this._cleanConditionally(e,"table"),this._cleanConditionally(e,"ul"),this._cleanConditionally(e,"div"),this._replaceNodeTags(this._getAllNodesWithTag(e,["h1"]),"h2"),this._removeNodes(this._getAllNodesWithTag(e,["p"]),(function(e){return 0===e.getElementsByTagName("img").length+e.getElementsByTagName("embed").length+e.getElementsByTagName("object").length+e.getElementsByTagName("iframe").length&&!this._getInnerText(e,!1)})),this._forEachNode(this._getAllNodesWithTag(e,["br"]),(function(e){var t=this._nextNode(e.nextSibling);t&&"P"==t.tagName&&e.parentNode.removeChild(e)})),this._forEachNode(this._getAllNodesWithTag(e,["table"]),(function(e){var t=this._hasSingleTagInsideElement(e,"TBODY")?e.firstElementChild:e;if(this._hasSingleTagInsideElement(t,"TR")){var n=t.firstElementChild;if(this._hasSingleTagInsideElement(n,"TD")){var i=n.firstElementChild;i=this._setNodeTag(i,this._everyNode(i.childNodes,this._isPhrasingContent)?"P":"DIV"),e.parentNode.replaceChild(i,e)}}}))},_initializeNode:function(e){switch(e.readability={contentScore:0},e.tagName){case"DIV":e.readability.contentScore+=5;break;case"PRE":case"TD":case"BLOCKQUOTE":e.readability.contentScore+=3;break;case"ADDRESS":case"OL":case"UL":case"DL":case"DD":case"DT":case"LI":case"FORM":e.readability.contentScore-=3;break;case"H1":case"H2":case"H3":case"H4":case"H5":case"H6":case"TH":e.readability.contentScore-=5}e.readability.contentScore+=this._getClassWeight(e)},_removeAndGetNext:function(e){var t=this._getNextNode(e,!0);return e.parentNode.removeChild(e),t},_getNextNode:function(e,t){if(!t&&e.firstElementChild)return e.firstElementChild;if(e.nextElementSibling)return e.nextElementSibling;do{e=e.parentNode}while(e&&!e.nextElementSibling);return e&&e.nextElementSibling},_textSimilarity:function(e,t){var n=e.toLowerCase().split(this.REGEXPS.tokenize).filter(Boolean),i=t.toLowerCase().split(this.REGEXPS.tokenize).filter(Boolean);return n.length&&i.length?1-i.filter((e=>!n.includes(e))).join(" ").length/i.join(" ").length:0},_checkByline:function(e,t){if(this._articleByline)return!1;if(void 0!==e.getAttribute)var n=e.getAttribute("rel"),i=e.getAttribute("itemprop");return!(!("author"===n||i&&-1!==i.indexOf("author")||this.REGEXPS.byline.test(t))||!this._isValidByline(e.textContent)||(this._articleByline=e.textContent.trim(),0))},_getNodeAncestors:function(e,t){t=t||0;for(var n=0,i=[];e.parentNode&&(i.push(e.parentNode),!t||++n!==t);)e=e.parentNode;return i},_grabArticle:function(e){this.log("**** grabArticle ****");var t=this._doc,n=null!==e;if(!(e=e||this._doc.body))return this.log("No body found in document. Abort."),null;for(var i=e.innerHTML;;){this.log("Starting grabArticle loop");var r=this._flagIsActive(this.FLAG_STRIP_UNLIKELYS),o=[],s=this._doc.documentElement;let F=!0;for(;s;){"HTML"===s.tagName&&(this._articleLang=s.getAttribute("lang"));var a=s.className+" "+s.id;if(this._isProbablyVisible(s))if(this._checkByline(s,a))s=this._removeAndGetNext(s);else if(F&&this._headerDuplicatesTitle(s))this.log("Removing header: ",s.textContent.trim(),this._articleTitle.trim()),F=!1,s=this._removeAndGetNext(s);else{if(r){if(this.REGEXPS.unlikelyCandidates.test(a)&&!this.REGEXPS.okMaybeItsACandidate.test(a)&&!this._hasAncestorTag(s,"table")&&!this._hasAncestorTag(s,"code")&&"BODY"!==s.tagName&&"A"!==s.tagName){this.log("Removing unlikely candidate - "+a),s=this._removeAndGetNext(s);continue}if(this.UNLIKELY_ROLES.includes(s.getAttribute("role"))){this.log("Removing content with role "+s.getAttribute("role")+" - "+a),s=this._removeAndGetNext(s);continue}}if("DIV"!==s.tagName&&"SECTION"!==s.tagName&&"HEADER"!==s.tagName&&"H1"!==s.tagName&&"H2"!==s.tagName&&"H3"!==s.tagName&&"H4"!==s.tagName&&"H5"!==s.tagName&&"H6"!==s.tagName||!this._isElementWithoutContent(s)){if(-1!==this.DEFAULT_TAGS_TO_SCORE.indexOf(s.tagName)&&o.push(s),"DIV"===s.tagName){for(var l=null,c=s.firstChild;c;){var u=c.nextSibling;if(this._isPhrasingContent(c))null!==l?l.appendChild(c):this._isWhitespace(c)||(l=t.createElement("p"),s.replaceChild(l,c),l.appendChild(c));else if(null!==l){for(;l.lastChild&&this._isWhitespace(l.lastChild);)l.removeChild(l.lastChild);l=null}c=u}if(this._hasSingleTagInsideElement(s,"P")&&this._getLinkDensity(s)<.25){var d=s.children[0];s.parentNode.replaceChild(d,s),s=d,o.push(s)}else this._hasChildBlockElement(s)||(s=this._setNodeTag(s,"P"),o.push(s))}s=this._getNextNode(s)}else s=this._removeAndGetNext(s)}else this.log("Removing hidden node - "+a),s=this._removeAndGetNext(s)}var h=[];this._forEachNode(o,(function(e){if(e.parentNode&&void 0!==e.parentNode.tagName){var t=this._getInnerText(e);if(!(t.length<25)){var n=this._getNodeAncestors(e,5);if(0!==n.length){var i=0;i+=1,i+=t.split(",").length,i+=Math.min(Math.floor(t.length/100),3),this._forEachNode(n,(function(e,t){if(e.tagName&&e.parentNode&&void 0!==e.parentNode.tagName){if(void 0===e.readability&&(this._initializeNode(e),h.push(e)),0===t)var n=1;else n=1===t?2:3*t;e.readability.contentScore+=i/n}}))}}}}));for(var f=[],g=0,m=h.length;g<m;g+=1){var p=h[g],y=p.readability.contentScore*(1-this._getLinkDensity(p));p.readability.contentScore=y,this.log("Candidate:",p,"with score "+y);for(var v=0;v<this._nbTopCandidates;v++){var b=f[v];if(!b||y>b.readability.contentScore){f.splice(v,0,p),f.length>this._nbTopCandidates&&f.pop();break}}}var _,E=f[0]||null,N=!1;if(null===E||"BODY"===E.tagName){for(E=t.createElement("DIV"),N=!0;e.firstChild;)this.log("Moving child out:",e.firstChild),E.appendChild(e.firstChild);e.appendChild(E),this._initializeNode(E)}else if(E){for(var A=[],T=1;T<f.length;T++)f[T].readability.contentScore/E.readability.contentScore>=.75&&A.push(this._getNodeAncestors(f[T]));if(A.length>=3)for(_=E.parentNode;"BODY"!==_.tagName;){for(var C=0,S=0;S<A.length&&C<3;S++)C+=Number(A[S].includes(_));if(C>=3){E=_;break}_=_.parentNode}E.readability||this._initializeNode(E),_=E.parentNode;for(var w=E.readability.contentScore,x=w/3;"BODY"!==_.tagName;)if(_.readability){var L=_.readability.contentScore;if(L<x)break;if(L>w){E=_;break}w=_.readability.contentScore,_=_.parentNode}else _=_.parentNode;for(_=E.parentNode;"BODY"!=_.tagName&&1==_.children.length;)_=(E=_).parentNode;E.readability||this._initializeNode(E)}var P=t.createElement("DIV");n&&(P.id="readability-content");for(var O=Math.max(10,.2*E.readability.contentScore),I=(_=E.parentNode).children,R=0,D=I.length;R<D;R++){var M=I[R],k=!1;if(this.log("Looking at sibling node:",M,M.readability?"with score "+M.readability.contentScore:""),this.log("Sibling has score",M.readability?M.readability.contentScore:"Unknown"),M===E)k=!0;else{var B=0;if(M.className===E.className&&""!==E.className&&(B+=.2*E.readability.contentScore),M.readability&&M.readability.contentScore+B>=O)k=!0;else if("P"===M.nodeName){var H=this._getLinkDensity(M),U=this._getInnerText(M),j=U.length;(j>80&&H<.25||j<80&&j>0&&0===H&&-1!==U.search(/\.( |$)/))&&(k=!0)}}k&&(this.log("Appending node:",M),-1===this.ALTER_TO_DIV_EXCEPTIONS.indexOf(M.nodeName)&&(this.log("Altering sibling:",M,"to div."),M=this._setNodeTag(M,"DIV")),P.appendChild(M),I=_.children,R-=1,D-=1)}if(this._debug&&this.log("Article content pre-prep: "+P.innerHTML),this._prepArticle(P),this._debug&&this.log("Article content post-prep: "+P.innerHTML),N)E.id="readability-page-1",E.className="page";else{var $=t.createElement("DIV");for($.id="readability-page-1",$.className="page";P.firstChild;)$.appendChild(P.firstChild);P.appendChild($)}this._debug&&this.log("Article content after paging: "+P.innerHTML);var G=!0,V=this._getInnerText(P,!0).length;if(V<this._charThreshold)if(G=!1,e.innerHTML=i,this._flagIsActive(this.FLAG_STRIP_UNLIKELYS))this._removeFlag(this.FLAG_STRIP_UNLIKELYS),this._attempts.push({articleContent:P,textLength:V});else if(this._flagIsActive(this.FLAG_WEIGHT_CLASSES))this._removeFlag(this.FLAG_WEIGHT_CLASSES),this._attempts.push({articleContent:P,textLength:V});else if(this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY))this._removeFlag(this.FLAG_CLEAN_CONDITIONALLY),this._attempts.push({articleContent:P,textLength:V});else{if(this._attempts.push({articleContent:P,textLength:V}),this._attempts.sort((function(e,t){return t.textLength-e.textLength})),!this._attempts[0].textLength)return null;P=this._attempts[0].articleContent,G=!0}if(G){var W=[_,E].concat(this._getNodeAncestors(_));return this._someNode(W,(function(e){if(!e.tagName)return!1;var t=e.getAttribute("dir");return!!t&&(this._articleDir=t,!0)})),P}}},_isValidByline:function(e){return("string"==typeof e||e instanceof String)&&(e=e.trim()).length>0&&e.length<100},_unescapeHtmlEntities:function(e){if(!e)return e;var t=this.HTML_ESCAPE_MAP;return e.replace(/&(quot|amp|apos|lt|gt);/g,(function(e,n){return t[n]})).replace(/&#(?:x([0-9a-z]{1,4})|([0-9]{1,4}));/gi,(function(e,t,n){var i=parseInt(t||n,t?16:10);return String.fromCharCode(i)}))},_getJSONLD:function(e){var t,n=this._getAllNodesWithTag(e,["script"]);return this._forEachNode(n,(function(e){if(!t&&"application/ld+json"===e.getAttribute("type"))try{var n=e.textContent.replace(/^\s*<!\[CDATA\[|\]\]>\s*$/g,""),i=JSON.parse(n);if(!i["@context"]||!i["@context"].match(/^https?\:\/\/schema\.org$/))return;if(!i["@type"]&&Array.isArray(i["@graph"])&&(i=i["@graph"].find((function(e){return(e["@type"]||"").match(this.REGEXPS.jsonLdArticleTypes)}))),!i||!i["@type"]||!i["@type"].match(this.REGEXPS.jsonLdArticleTypes))return;if(t={},"string"==typeof i.name&&"string"==typeof i.headline&&i.name!==i.headline){var r=this._getArticleTitle(),o=this._textSimilarity(i.name,r)>.75,s=this._textSimilarity(i.headline,r)>.75;t.title=s&&!o?i.headline:i.name}else"string"==typeof i.name?t.title=i.name.trim():"string"==typeof i.headline&&(t.title=i.headline.trim());return i.author&&("string"==typeof i.author.name?t.byline=i.author.name.trim():Array.isArray(i.author)&&i.author[0]&&"string"==typeof i.author[0].name&&(t.byline=i.author.filter((function(e){return e&&"string"==typeof e.name})).map((function(e){return e.name.trim()})).join(", "))),"string"==typeof i.description&&(t.excerpt=i.description.trim()),void(i.publisher&&"string"==typeof i.publisher.name&&(t.siteName=i.publisher.name.trim()))}catch(e){this.log(e.message)}})),t||{}},_getArticleMetadata:function(e){var t={},n={},i=this._doc.getElementsByTagName("meta"),r=/\s*(dc|dcterm|og|twitter)\s*:\s*(author|creator|description|title|site_name)\s*/gi,o=/^\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\s*[\.:]\s*)?(author|creator|description|title|site_name)\s*$/i;return this._forEachNode(i,(function(e){var t=e.getAttribute("name"),i=e.getAttribute("property"),s=e.getAttribute("content");if(s){var a=null,l=null;i&&(a=i.match(r))&&(l=a[0].toLowerCase().replace(/\s/g,""),n[l]=s.trim()),!a&&t&&o.test(t)&&(l=t,s&&(l=l.toLowerCase().replace(/\s/g,"").replace(/\./g,":"),n[l]=s.trim()))}})),t.title=e.title||n["dc:title"]||n["dcterm:title"]||n["og:title"]||n["weibo:article:title"]||n["weibo:webpage:title"]||n.title||n["twitter:title"],t.title||(t.title=this._getArticleTitle()),t.byline=e.byline||n["dc:creator"]||n["dcterm:creator"]||n.author,t.excerpt=e.excerpt||n["dc:description"]||n["dcterm:description"]||n["og:description"]||n["weibo:article:description"]||n["weibo:webpage:description"]||n.description||n["twitter:description"],t.siteName=e.siteName||n["og:site_name"],t.title=this._unescapeHtmlEntities(t.title),t.byline=this._unescapeHtmlEntities(t.byline),t.excerpt=this._unescapeHtmlEntities(t.excerpt),t.siteName=this._unescapeHtmlEntities(t.siteName),t},_isSingleImage:function(e){return"IMG"===e.tagName||1===e.children.length&&""===e.textContent.trim()&&this._isSingleImage(e.children[0])},_unwrapNoscriptImages:function(e){var t=Array.from(e.getElementsByTagName("img"));this._forEachNode(t,(function(e){for(var t=0;t<e.attributes.length;t++){var n=e.attributes[t];switch(n.name){case"src":case"srcset":case"data-src":case"data-srcset":return}if(/\.(jpg|jpeg|png|webp)/i.test(n.value))return}e.parentNode.removeChild(e)}));var n=Array.from(e.getElementsByTagName("noscript"));this._forEachNode(n,(function(t){var n=e.createElement("div");if(n.innerHTML=t.innerHTML,this._isSingleImage(n)){var i=t.previousElementSibling;if(i&&this._isSingleImage(i)){var r=i;"IMG"!==r.tagName&&(r=i.getElementsByTagName("img")[0]);for(var o=n.getElementsByTagName("img")[0],s=0;s<r.attributes.length;s++){var a=r.attributes[s];if(""!==a.value&&("src"===a.name||"srcset"===a.name||/\.(jpg|jpeg|png|webp)/i.test(a.value))){if(o.getAttribute(a.name)===a.value)continue;var l=a.name;o.hasAttribute(l)&&(l="data-old-"+l),o.setAttribute(l,a.value)}}t.parentNode.replaceChild(n.firstElementChild,i)}}}))},_removeScripts:function(e){this._removeNodes(this._getAllNodesWithTag(e,["script"]),(function(e){return e.nodeValue="",e.removeAttribute("src"),!0})),this._removeNodes(this._getAllNodesWithTag(e,["noscript"]))},_hasSingleTagInsideElement:function(e,t){return 1==e.children.length&&e.children[0].tagName===t&&!this._someNode(e.childNodes,(function(e){return e.nodeType===this.TEXT_NODE&&this.REGEXPS.hasContent.test(e.textContent)}))},_isElementWithoutContent:function(e){return e.nodeType===this.ELEMENT_NODE&&0==e.textContent.trim().length&&(0==e.children.length||e.children.length==e.getElementsByTagName("br").length+e.getElementsByTagName("hr").length)},_hasChildBlockElement:function(e){return this._someNode(e.childNodes,(function(e){return this.DIV_TO_P_ELEMS.has(e.tagName)||this._hasChildBlockElement(e)}))},_isPhrasingContent:function(e){return e.nodeType===this.TEXT_NODE||-1!==this.PHRASING_ELEMS.indexOf(e.tagName)||("A"===e.tagName||"DEL"===e.tagName||"INS"===e.tagName)&&this._everyNode(e.childNodes,this._isPhrasingContent)},_isWhitespace:function(e){return e.nodeType===this.TEXT_NODE&&0===e.textContent.trim().length||e.nodeType===this.ELEMENT_NODE&&"BR"===e.tagName},_getInnerText:function(e,t){t=void 0===t||t;var n=e.textContent.trim();return t?n.replace(this.REGEXPS.normalize," "):n},_getCharCount:function(e,t){return t=t||",",this._getInnerText(e).split(t).length-1},_cleanStyles:function(e){if(e&&"svg"!==e.tagName.toLowerCase()){for(var t=0;t<this.PRESENTATIONAL_ATTRIBUTES.length;t++)e.removeAttribute(this.PRESENTATIONAL_ATTRIBUTES[t]);-1!==this.DEPRECATED_SIZE_ATTRIBUTE_ELEMS.indexOf(e.tagName)&&(e.removeAttribute("width"),e.removeAttribute("height"));for(var n=e.firstElementChild;null!==n;)this._cleanStyles(n),n=n.nextElementSibling}},_getLinkDensity:function(e){var t=this._getInnerText(e).length;if(0===t)return 0;var n=0;return this._forEachNode(e.getElementsByTagName("a"),(function(e){var t=e.getAttribute("href"),i=t&&this.REGEXPS.hashUrl.test(t)?.3:1;n+=this._getInnerText(e).length*i})),n/t},_getClassWeight:function(e){if(!this._flagIsActive(this.FLAG_WEIGHT_CLASSES))return 0;var t=0;return"string"==typeof e.className&&""!==e.className&&(this.REGEXPS.negative.test(e.className)&&(t-=25),this.REGEXPS.positive.test(e.className)&&(t+=25)),"string"==typeof e.id&&""!==e.id&&(this.REGEXPS.negative.test(e.id)&&(t-=25),this.REGEXPS.positive.test(e.id)&&(t+=25)),t},_clean:function(e,t){var n=-1!==["object","embed","iframe"].indexOf(t);this._removeNodes(this._getAllNodesWithTag(e,[t]),(function(e){if(n){for(var t=0;t<e.attributes.length;t++)if(this.REGEXPS.videos.test(e.attributes[t].value))return!1;if("object"===e.tagName&&this.REGEXPS.videos.test(e.innerHTML))return!1}return!0}))},_hasAncestorTag:function(e,t,n,i){n=n||3,t=t.toUpperCase();for(var r=0;e.parentNode;){if(n>0&&r>n)return!1;if(e.parentNode.tagName===t&&(!i||i(e.parentNode)))return!0;e=e.parentNode,r++}return!1},_getRowAndColumnCount:function(e){for(var t=0,n=0,i=e.getElementsByTagName("tr"),r=0;r<i.length;r++){var o=i[r].getAttribute("rowspan")||0;o&&(o=parseInt(o,10)),t+=o||1;for(var s=0,a=i[r].getElementsByTagName("td"),l=0;l<a.length;l++){var c=a[l].getAttribute("colspan")||0;c&&(c=parseInt(c,10)),s+=c||1}n=Math.max(n,s)}return{rows:t,columns:n}},_markDataTables:function(e){for(var t=e.getElementsByTagName("table"),n=0;n<t.length;n++){var i=t[n];if("presentation"!=i.getAttribute("role"))if("0"!=i.getAttribute("datatable"))if(i.getAttribute("summary"))i._readabilityDataTable=!0;else{var r=i.getElementsByTagName("caption")[0];if(r&&r.childNodes.length>0)i._readabilityDataTable=!0;else if(["col","colgroup","tfoot","thead","th"].some((function(e){return!!i.getElementsByTagName(e)[0]})))this.log("Data table because found data-y descendant"),i._readabilityDataTable=!0;else if(i.getElementsByTagName("table")[0])i._readabilityDataTable=!1;else{var o=this._getRowAndColumnCount(i);o.rows>=10||o.columns>4?i._readabilityDataTable=!0:i._readabilityDataTable=o.rows*o.columns>10}}else i._readabilityDataTable=!1;else i._readabilityDataTable=!1}},_fixLazyImages:function(e){this._forEachNode(this._getAllNodesWithTag(e,["img","picture","figure"]),(function(e){if(e.src&&this.REGEXPS.b64DataUrl.test(e.src)){if("image/svg+xml"===this.REGEXPS.b64DataUrl.exec(e.src)[1])return;for(var t=!1,n=0;n<e.attributes.length;n++){var i=e.attributes[n];if("src"!==i.name&&/\.(jpg|jpeg|png|webp)/i.test(i.value)){t=!0;break}}if(t){var r=e.src.search(/base64\s*/i)+7;e.src.length-r<133&&e.removeAttribute("src")}}if(!(e.src||e.srcset&&"null"!=e.srcset)||-1!==e.className.toLowerCase().indexOf("lazy"))for(var o=0;o<e.attributes.length;o++)if("src"!==(i=e.attributes[o]).name&&"srcset"!==i.name&&"alt"!==i.name){var s=null;if(/\.(jpg|jpeg|png|webp)\s+\d/.test(i.value)?s="srcset":/^\s*\S+\.(jpg|jpeg|png|webp)\S*\s*$/.test(i.value)&&(s="src"),s)if("IMG"===e.tagName||"PICTURE"===e.tagName)e.setAttribute(s,i.value);else if("FIGURE"===e.tagName&&!this._getAllNodesWithTag(e,["img","picture"]).length){var a=this._doc.createElement("img");a.setAttribute(s,i.value),e.appendChild(a)}}}))},_getTextDensity:function(e,t){var n=this._getInnerText(e,!0).length;if(0===n)return 0;var i=0,r=this._getAllNodesWithTag(e,t);return this._forEachNode(r,(e=>i+=this._getInnerText(e,!0).length)),i/n},_cleanConditionally:function(e,t){this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY)&&this._removeNodes(this._getAllNodesWithTag(e,[t]),(function(e){var n=function(e){return e._readabilityDataTable},i="ul"===t||"ol"===t;if(!i){var r=0,o=this._getAllNodesWithTag(e,["ul","ol"]);this._forEachNode(o,(e=>r+=this._getInnerText(e).length)),i=r/this._getInnerText(e).length>.9}if("table"===t&&n(e))return!1;if(this._hasAncestorTag(e,"table",-1,n))return!1;if(this._hasAncestorTag(e,"code"))return!1;var s=this._getClassWeight(e);if(this.log("Cleaning Conditionally",e),s+0<0)return!0;if(this._getCharCount(e,",")<10){for(var a=e.getElementsByTagName("p").length,l=e.getElementsByTagName("img").length,c=e.getElementsByTagName("li").length-100,u=e.getElementsByTagName("input").length,d=this._getTextDensity(e,["h1","h2","h3","h4","h5","h6"]),h=0,f=this._getAllNodesWithTag(e,["object","embed","iframe"]),g=0;g<f.length;g++){for(var m=0;m<f[g].attributes.length;m++)if(this.REGEXPS.videos.test(f[g].attributes[m].value))return!1;if("object"===f[g].tagName&&this.REGEXPS.videos.test(f[g].innerHTML))return!1;h++}var p=this._getLinkDensity(e),y=this._getInnerText(e).length;return l>1&&a/l<.5&&!this._hasAncestorTag(e,"figure")||!i&&c>a||u>Math.floor(a/3)||!i&&d<.9&&y<25&&(0===l||l>2)&&!this._hasAncestorTag(e,"figure")||!i&&s<25&&p>.2||s>=25&&p>.5||1===h&&y<75||h>1}return!1}))},_cleanMatchedNodes:function(e,t){for(var n=this._getNextNode(e,!0),i=this._getNextNode(e);i&&i!=n;)i=t.call(this,i,i.className+" "+i.id)?this._removeAndGetNext(i):this._getNextNode(i)},_cleanHeaders:function(e){let t=this._getAllNodesWithTag(e,["h1","h2"]);this._removeNodes(t,(function(e){let t=this._getClassWeight(e)<0;return t&&this.log("Removing header with low class weight:",e),t}))},_headerDuplicatesTitle:function(e){if("H1"!=e.tagName&&"H2"!=e.tagName)return!1;var t=this._getInnerText(e,!1);return this.log("Evaluating similarity of header:",t,this._articleTitle),this._textSimilarity(this._articleTitle,t)>.75},_flagIsActive:function(e){return(this._flags&e)>0},_removeFlag:function(e){this._flags=this._flags&~e},_isProbablyVisible:function(e){return(!e.style||"none"!=e.style.display)&&!e.hasAttribute("hidden")&&(!e.hasAttribute("aria-hidden")||"true"!=e.getAttribute("aria-hidden")||e.className&&e.className.indexOf&&-1!==e.className.indexOf("fallback-image"))},parse:function(){if(this._maxElemsToParse>0){var e=this._doc.getElementsByTagName("*").length;if(e>this._maxElemsToParse)throw new Error("Aborting parsing document; "+e+" elements found")}this._unwrapNoscriptImages(this._doc);var t=this._disableJSONLD?{}:this._getJSONLD(this._doc);this._removeScripts(this._doc),this._prepDocument();var n=this._getArticleMetadata(t);this._articleTitle=n.title;var i=this._grabArticle();if(!i)return null;if(this.log("Grabbed: "+i.innerHTML),this._postProcessContent(i),!n.excerpt){var r=i.getElementsByTagName("p");r.length>0&&(n.excerpt=r[0].textContent.trim())}var o=i.textContent;return{title:this._articleTitle,byline:n.byline||this._articleByline,dir:this._articleDir,lang:this._articleLang,content:this._serializer(i),textContent:o,length:o.length,excerpt:n.excerpt,siteName:n.siteName||this._articleSiteName}}},e.exports=t},107:(e,t,n)=>{var i=n(174),r=n(893);e.exports={Readability:i,isProbablyReaderable:r}},763:(e,t,n)=>{"use strict";var i;n.r(t),n.d(t,{AttributeAction:()=>o,IgnoreCaseMode:()=>r,SelectorType:()=>i,isTraversal:()=>u,parse:()=>p,stringify:()=>A}),function(e){e.Attribute="attribute",e.Pseudo="pseudo",e.PseudoElement="pseudo-element",e.Tag="tag",e.Universal="universal",e.Adjacent="adjacent",e.Child="child",e.Descendant="descendant",e.Parent="parent",e.Sibling="sibling",e.ColumnCombinator="column-combinator"}(i||(i={}));const r={Unknown:null,QuirksMode:"quirks",IgnoreCase:!0,CaseSensitive:!1};var o;!function(e){e.Any="any",e.Element="element",e.End="end",e.Equals="equals",e.Exists="exists",e.Hyphen="hyphen",e.Not="not",e.Start="start"}(o||(o={}));const s=/^[^\\#]?(?:\\(?:[\da-f]{1,6}\s?|.)|[\w\-\u00b0-\uFFFF])+/,a=/\\([\da-f]{1,6}\s?|(\s)|.)/gi,l=new Map([[126,o.Element],[94,o.Start],[36,o.End],[42,o.Any],[33,o.Not],[124,o.Hyphen]]),c=new Set(["has","not","matches","is","where","host","host-context"]);function u(e){switch(e.type){case i.Adjacent:case i.Child:case i.Descendant:case i.Parent:case i.Sibling:case i.ColumnCombinator:return!0;default:return!1}}const d=new Set(["contains","icontains"]);function h(e,t,n){const i=parseInt(t,16)-65536;return i!=i||n?t:i<0?String.fromCharCode(i+65536):String.fromCharCode(i>>10|55296,1023&i|56320)}function f(e){return e.replace(a,h)}function g(e){return 39===e||34===e}function m(e){return 32===e||9===e||10===e||12===e||13===e}function p(e){const t=[],n=y(t,`${e}`,0);if(n<e.length)throw new Error(`Unmatched selector: ${e.slice(n)}`);return t}function y(e,t,n){let r=[];function a(e){const i=t.slice(n+e).match(s);if(!i)throw new Error(`Expected name, found ${t.slice(n)}`);const[r]=i;return n+=e+r.length,f(r)}function h(e){for(n+=e;n<t.length&&m(t.charCodeAt(n));)n++}function p(){const e=n+=1;let i=1;for(;i>0&&n<t.length;n++)40!==t.charCodeAt(n)||v(n)?41!==t.charCodeAt(n)||v(n)||i--:i++;if(i)throw new Error("Parenthesis not matched");return f(t.slice(e,n-1))}function v(e){let n=0;for(;92===t.charCodeAt(--e);)n++;return 1==(1&n)}function b(){if(r.length>0&&u(r[r.length-1]))throw new Error("Did not expect successive traversals.")}function _(e){r.length>0&&r[r.length-1].type===i.Descendant?r[r.length-1].type=e:(b(),r.push({type:e}))}function E(e,t){r.push({type:i.Attribute,name:e,action:t,value:a(1),namespace:null,ignoreCase:"quirks"})}function N(){if(r.length&&r[r.length-1].type===i.Descendant&&r.pop(),0===r.length)throw new Error("Empty sub-selector");e.push(r)}if(h(0),t.length===n)return n;e:for(;n<t.length;){const e=t.charCodeAt(n);switch(e){case 32:case 9:case 10:case 12:case 13:0!==r.length&&r[0].type===i.Descendant||(b(),r.push({type:i.Descendant})),h(1);break;case 62:_(i.Child),h(1);break;case 60:_(i.Parent),h(1);break;case 126:_(i.Sibling),h(1);break;case 43:_(i.Adjacent),h(1);break;case 46:E("class",o.Element);break;case 35:E("id",o.Equals);break;case 91:{let e;h(1);let s=null;124===t.charCodeAt(n)?e=a(1):t.startsWith("*|",n)?(s="*",e=a(2)):(e=a(0),124===t.charCodeAt(n)&&61!==t.charCodeAt(n+1)&&(s=e,e=a(1))),h(0);let c=o.Exists;const u=l.get(t.charCodeAt(n));if(u){if(c=u,61!==t.charCodeAt(n+1))throw new Error("Expected `=`");h(2)}else 61===t.charCodeAt(n)&&(c=o.Equals,h(1));let d="",p=null;if("exists"!==c){if(g(t.charCodeAt(n))){const e=t.charCodeAt(n);let i=n+1;for(;i<t.length&&(t.charCodeAt(i)!==e||v(i));)i+=1;if(t.charCodeAt(i)!==e)throw new Error("Attribute value didn't end");d=f(t.slice(n+1,i)),n=i+1}else{const e=n;for(;n<t.length&&(!m(t.charCodeAt(n))&&93!==t.charCodeAt(n)||v(n));)n+=1;d=f(t.slice(e,n))}h(0);const e=32|t.charCodeAt(n);115===e?(p=!1,h(1)):105===e&&(p=!0,h(1))}if(93!==t.charCodeAt(n))throw new Error("Attribute selector didn't terminate");n+=1;const y={type:i.Attribute,name:e,action:c,value:d,namespace:s,ignoreCase:p};r.push(y);break}case 58:{if(58===t.charCodeAt(n+1)){r.push({type:i.PseudoElement,name:a(2).toLowerCase(),data:40===t.charCodeAt(n)?p():null});continue}const e=a(1).toLowerCase();let o=null;if(40===t.charCodeAt(n))if(c.has(e)){if(g(t.charCodeAt(n+1)))throw new Error(`Pseudo-selector ${e} cannot be quoted`);if(o=[],n=y(o,t,n+1),41!==t.charCodeAt(n))throw new Error(`Missing closing parenthesis in :${e} (${t})`);n+=1}else{if(o=p(),d.has(e)){const e=o.charCodeAt(0);e===o.charCodeAt(o.length-1)&&g(e)&&(o=o.slice(1,-1))}o=f(o)}r.push({type:i.Pseudo,name:e,data:o});break}case 44:N(),r=[],h(1);break;default:{if(t.startsWith("/*",n)){const e=t.indexOf("*/",n+2);if(e<0)throw new Error("Comment was not terminated");n=e+2,0===r.length&&h(0);break}let o,l=null;if(42===e)n+=1,o="*";else if(124===e){if(o="",124===t.charCodeAt(n+1)){_(i.ColumnCombinator),h(2);break}}else{if(!s.test(t.slice(n)))break e;o=a(0)}124===t.charCodeAt(n)&&124!==t.charCodeAt(n+1)&&(l=o,42===t.charCodeAt(n+1)?(o="*",n+=2):o=a(1)),r.push("*"===o?{type:i.Universal,namespace:l}:{type:i.Tag,name:o,namespace:l})}}}return N(),n}const v=["\\",'"',"%","'"],b=[...v,"(",")"],_=new Set(v.map((e=>e.charCodeAt(0)))),E=new Set(b.map((e=>e.charCodeAt(0)))),N=new Set([...b,"~","^","$","*","+","!","|",":","[","]"," ","."].map((e=>e.charCodeAt(0))));function A(e){return e.map((e=>e.map(T).join(""))).join(", ")}function T(e,t,n){switch(e.type){case i.Child:return 0===t?"> ":" > ";case i.Parent:return 0===t?"< ":" < ";case i.Sibling:return 0===t?"~ ":" ~ ";case i.Adjacent:return 0===t?"+ ":" + ";case i.Descendant:return" ";case i.ColumnCombinator:return 0===t?"|| ":" || ";case i.Universal:return"*"===e.namespace&&t+1<n.length&&"name"in n[t+1]?"":`${S(e.namespace)}*`;case i.Tag:return C(e);case i.PseudoElement:return`::${w(e.name,N)}${null===e.data?"":`(${w(e.data,E)})`}`;case i.Pseudo:return`:${w(e.name,N)}${null===e.data?"":`(${"string"==typeof e.data?w(e.data,E):A(e.data)})`}`;case i.Attribute:{if("id"===e.name&&e.action===o.Equals&&"quirks"===e.ignoreCase&&!e.namespace)return`#${w(e.value,N)}`;if("class"===e.name&&e.action===o.Element&&"quirks"===e.ignoreCase&&!e.namespace)return`.${w(e.value,N)}`;const t=C(e);return e.action===o.Exists?`[${t}]`:`[${t}${function(e){switch(e){case o.Equals:return"";case o.Element:return"~";case o.Start:return"^";case o.End:return"$";case o.Any:return"*";case o.Not:return"!";case o.Hyphen:return"|";case o.Exists:throw new Error("Shouldn't be here")}}(e.action)}="${w(e.value,_)}"${null===e.ignoreCase?"":e.ignoreCase?" i":" s"}]`}}}function C(e){return`${S(e.namespace)}${w(e.name,N)}`}function S(e){return null!==e?`${"*"===e?"*":w(e,N)}|`:""}function w(e,t){let n=0,i="";for(let r=0;r<e.length;r++)t.has(e.charCodeAt(r))&&(i+=`${e.slice(n,r)}\\${e.charAt(r)}`,n=r+1);return i.length>0?i+e.slice(n):e}},482:(e,t,n)=>{"use strict";n.r(t),n.d(t,{app:()=>E,h:()=>_,memo:()=>v,text:()=>b});var i={},r=[],o=e=>e,s=r.map,a=Array.isArray,l="undefined"!=typeof requestAnimationFrame?requestAnimationFrame:setTimeout,c=e=>{var t="";if("string"==typeof e)return e;if(a(e))for(var n,i=0;i<e.length;i++)(n=c(e[i]))&&(t+=(t&&" ")+n);else for(var i in e)e[i]&&(t+=(t&&" ")+i);return t},u=(e,t)=>{for(var n in{...e,...t})if("function"==typeof(a(e[n])?e[n][0]:e[n]))t[n]=e[n];else if(e[n]!==t[n])return!0},d=e=>null==e?e:e.key,h=(e,t,n,i,r,o)=>{if("style"===t)for(var s in{...n,...i})n=null==i||null==i[s]?"":i[s],"-"===s[0]?e[t].setProperty(s,n):e[t][s]=n;else"o"===t[0]&&"n"===t[1]?((e.events||(e.events={}))[t=t.slice(2)]=i)?n||e.addEventListener(t,r):e.removeEventListener(t,r):!o&&"list"!==t&&"form"!==t&&t in e?e[t]=null==i?"":i:null==i||!1===i?e.removeAttribute(t):e.setAttribute(t,i)},f=(e,t,n)=>{var i=e.props,r=3===e.type?document.createTextNode(e.tag):(n=n||"svg"===e.tag)?document.createElementNS("http://www.w3.org/2000/svg",e.tag,i.is&&i):document.createElement(e.tag,i.is&&i);for(var o in i)h(r,o,null,i[o],t,n);for(var s=0;s<e.children.length;s++)r.appendChild(f(e.children[s]=m(e.children[s]),t,n));return e.node=r},g=(e,t,n,i,r,o)=>{if(n===i);else if(null!=n&&3===n.type&&3===i.type)n.tag!==i.tag&&(t.nodeValue=i.tag);else if(null==n||n.tag!==i.tag)t=e.insertBefore(f(i=m(i),r,o),t),null!=n&&e.removeChild(n.node);else{var s,a,l,c,u=n.props,p=i.props,y=n.children,v=i.children,b=0,_=0,E=y.length-1,N=v.length-1;for(var A in o=o||"svg"===i.tag,{...u,...p})("value"===A||"selected"===A||"checked"===A?t[A]:u[A])!==p[A]&&h(t,A,u[A],p[A],r,o);for(;_<=N&&b<=E&&null!=(l=d(y[b]))&&l===d(v[_]);)g(t,y[b].node,y[b],v[_]=m(v[_++],y[b++]),r,o);for(;_<=N&&b<=E&&null!=(l=d(y[E]))&&l===d(v[N]);)g(t,y[E].node,y[E],v[N]=m(v[N--],y[E--]),r,o);if(b>E)for(;_<=N;)t.insertBefore(f(v[_]=m(v[_++]),r,o),(a=y[b])&&a.node);else if(_>N)for(;b<=E;)t.removeChild(y[b++].node);else{var T={},C={};for(A=b;A<=E;A++)null!=(l=y[A].key)&&(T[l]=y[A]);for(;_<=N;)l=d(a=y[b]),c=d(v[_]=m(v[_],a)),C[l]||null!=c&&c===d(y[b+1])?(null==l&&t.removeChild(a.node),b++):null==c||1===n.type?(null==l&&(g(t,a&&a.node,a,v[_],r,o),_++),b++):(l===c?(g(t,a.node,a,v[_],r,o),C[c]=!0,b++):null!=(s=T[c])?(g(t,t.insertBefore(s.node,a&&a.node),s,v[_],r,o),C[c]=!0):g(t,a&&a.node,null,v[_],r,o),_++);for(;b<=E;)null==d(a=y[b++])&&t.removeChild(a.node);for(var A in T)null==C[A]&&t.removeChild(T[A].node)}}return i.node=t},m=(e,t)=>!0!==e&&!1!==e&&e?"function"==typeof e.tag?((!t||null==t.memo||((e,t)=>{for(var n in e)if(e[n]!==t[n])return!0;for(var n in t)if(e[n]!==t[n])return!0})(t.memo,e.memo))&&((t=e.tag(e.memo)).memo=e.memo),t):e:b(""),p=e=>3===e.nodeType?b(e.nodeValue,e):y(e.nodeName.toLowerCase(),i,s.call(e.childNodes,p),1,e),y=(e,{key:t,...n},i,r,o)=>({tag:e,props:n,key:t,children:i,type:r,node:o}),v=(e,t)=>({tag:e,memo:t}),b=(e,t)=>y(e,i,r,3,t),_=(e,{class:t,...n},o=r)=>y(e,{...n,...t?{class:c(t)}:i},a(o)?o:[o]),E=({node:e,view:t,subscriptions:n,dispatch:s=o,init:c=i})=>{var d,h,f=e&&p(e),m=[],y=e=>{d!==e&&(null==(d=e)&&(s=n=v=o),n&&(m=((e,t=r,n)=>{for(var i,o,s=[],a=0;a<e.length||a<t.length;a++)i=e[a],o=t[a],s.push(o&&!0!==o?!i||o[0]!==i[0]||u(o[1],i[1])?[o[0],o[1],(i&&i[2](),o[0](n,o[1]))]:i:i&&i[2]());return s})(m,n(d),s)),t&&!h&&l(v,h=!0))},v=()=>e=g(e.parentNode,e,f,f=t(d),b,h=!1),b=function(e){s(this.events[e.type],e)};return(s=s(((e,t)=>"function"==typeof e?s(e(d,t)):a(e)?"function"==typeof e[0]?s(e[0],e[1]):e.slice(1).map((e=>e&&!0!==e&&(e[0]||e)(s,e[1])),y(e[0])):y(e))))(c),s}},302:(e,t,n)=>{"use strict";n.r(t),n.d(t,{calculate:()=>i,compare:()=>o});var i=function(e){var t,n,i,o,s=[];for(i=0,o=(t=e.split(",")).length;i<o;i+=1)(n=t[i]).length>0&&s.push(r(n));return s},r=function(e){var t,n,i=e,r={a:0,b:0,c:0},o=[];return t=function(t,n){var s,a,l,c,u,d;if(t.test(i))for(a=0,l=(s=i.match(t)).length;a<l;a+=1)r[n]+=1,c=s[a],u=i.indexOf(c),d=c.length,o.push({selector:e.substr(u,d),type:n,index:u,length:d}),i=i.replace(c,Array(d+1).join(" "))},(n=function(e){var t,n,r,o;if(e.test(i))for(n=0,r=(t=i.match(e)).length;n<r;n+=1)o=t[n],i=i.replace(o,Array(o.length+1).join("A"))})(/\\[0-9A-Fa-f]{6}\s?/g),n(/\\[0-9A-Fa-f]{1,5}\s/g),n(/\\./g),function(){var e,t,n,r,o=/{[^]*/gm;if(o.test(i))for(t=0,n=(e=i.match(o)).length;t<n;t+=1)r=e[t],i=i.replace(r,Array(r.length+1).join(" "))}(),t(/(\[[^\]]+\])/g,"b"),t(/(#[^\#\s\+>~\.\[:\)]+)/g,"a"),t(/(\.[^\s\+>~\.\[:\)]+)/g,"b"),t(/(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/gi,"c"),t(/(:(?!not|global|local)[\w-]+\([^\)]*\))/gi,"b"),t(/(:(?!not|global|local)[^\s\+>~\.\[:]+)/g,"b"),i=(i=(i=(i=(i=(i=i.replace(/[\*\s\+>~]/g," ")).replace(/[#\.]/g," ")).replace(/:not/g," ")).replace(/:local/g," ")).replace(/:global/g," ")).replace(/[\(\)]/g," "),t(/([^\s\+>~\.\[:]+)/g,"c"),o.sort((function(e,t){return e.index-t.index})),{selector:e,specificity:"0,"+r.a.toString()+","+r.b.toString()+","+r.c.toString(),specificityArray:[0,r.a,r.b,r.c],parts:o}},o=function(e,t){var n,i,o;if("string"==typeof e){if(-1!==e.indexOf(","))throw"Invalid CSS selector";n=r(e).specificityArray}else{if(!Array.isArray(e))throw"Invalid CSS selector or specificity array";if(4!==e.filter((function(e){return"number"==typeof e})).length)throw"Invalid specificity array";n=e}if("string"==typeof t){if(-1!==t.indexOf(","))throw"Invalid CSS selector";i=r(t).specificityArray}else{if(!Array.isArray(t))throw"Invalid CSS selector or specificity array";if(4!==t.filter((function(e){return"number"==typeof e})).length)throw"Invalid specificity array";i=t}for(o=0;o<4;o+=1){if(n[o]<i[o])return-1;if(n[o]>i[o])return 1}return 0}}},t={};function n(i){var r=t[i];if(void 0!==r)return r.exports;var o=t[i]={exports:{}};return e[i].call(o.exports,o,o.exports,n),o.exports}n.d=(e,t)=>{for(var i in t)n.o(t,i)&&!n.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{"use strict";const e=n(590);n.g.Clipper={clipArticle:e.clipArticle,clipPage:e.clipPage}})()})(); \ No newline at end of file +(()=>{var e={110:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.isSVGElement=t.cloneNode=void 0;const r=n(32),o=n(787),s=["altGlyph","altGlyphDef","altGlyphItem","animate","animateColor","animateMotion","animateTransform","circle","clipPath","color-profile","cursor","defs","desc","ellipse","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence","filter","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignObject","g","glyph","glyphRef","hkern","image","line","linearGradient","marker","mask","metadata","missing-glyph","mpath","path","pattern","polygon","polyline","radialGradient","rect","set","stop","svg","switch","symbol","text","textPath","title","tref","tspan","use","view","vkern"].map((e=>e.toLowerCase())),a=["script"].map((e=>e.toLowerCase()));function l(e){return!(!e||!e.tagName)&&s.includes(e.tagName.toLowerCase())}t.cloneNode=function e(t,n){return i(this,void 0,void 0,(function*(){const{root:c,filter:u}=n;if(!c&&u&&!u(t))return null;let d=yield function(e,t){try{if(e instanceof HTMLCanvasElement&&(null==t?void 0:t.images))return(0,r.createImage)(e.toDataURL(),null==t?void 0:t.fetchOptions);if(!(null==t?void 0:t.images)&&e instanceof HTMLImageElement)return null;if(!(null==t?void 0:t.styles)&&(e instanceof HTMLButtonElement||e instanceof HTMLFormElement||e instanceof HTMLSelectElement||e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement))return null;if(e.nodeType===Node.COMMENT_NODE)return null;if((n=e)&&n.tagName&&a.includes(n.tagName.toLowerCase()))return null;if(e.nodeType!==Node.TEXT_NODE&&!l(e)){const{display:t,width:n,height:i}=window.getComputedStyle(e);if("none"===t||"0px"===n&&"0px"===i)return null;if(function(e){return!(!e||!e.tagName)&&!s.includes(e.tagName.toLowerCase())&&e.tagName.includes("-")}(e)){const n=t.includes("inline"),i=document.createElement(n?"span":"div");for(const t of e.attributes)i.setAttribute(t.name,t.value);return i}}return e.cloneNode(!1)}catch(e){return console.error("Failed to clone element",e),null}var n}(t,n);if(!d)return null;d=yield function(t,n,r){return i(this,void 0,void 0,(function*(){const o=t.childNodes;return 0===o.length||(yield function(t,n,r){return i(this,void 0,void 0,(function*(){for(const i of n){const n=yield e(i,Object.assign(Object.assign({},r),{root:!1}));n&&t.appendChild(n)}}))}(n,o,r)),n}))}(t,d,n);const h=function(e,t,n){return t instanceof Element?(n.styles&&(function(e,t,n){const{getElementStyles:i}=n,r=i&&i(e);if(!r)return;var o,s;t.style.cssText=r.cssText,"body"===e.tagName.toLowerCase()&&(o=getComputedStyle(e),(s=t.style).font=o.font,s.fontFamily=o.fontFamily,s.fontFeatureSettings=o.fontFeatureSettings,s.fontKerning=o.fontKerning,s.fontSize=o.fontSize,s.fontStretch=o.fontStretch,s.fontStyle=o.fontStyle,s.fontVariant=o.fontVariant,s.fontVariantCaps=o.fontVariantCaps,s.fontVariantEastAsian=o.fontVariantEastAsian,s.fontVariantLigatures=o.fontVariantLigatures,s.fontVariantNumeric=o.fontVariantNumeric,s.fontVariationSettings=o.fontVariationSettings,s.fontWeight=o.fontWeight);const a=t.getAttribute("style");a&&t.setAttribute("style",a.replace(/(:?[:;])(:? +)/gm,((e,t)=>t)))}(e,t,n),function(e,t,n){const{getPseudoElementStyles:i}=n;let r=!1;const s=document.createElement("style"),a=`pseudo--${(0,o.uid)()}`;for(const t of[":before",":after"]){const n=i&&i(e,t)||getComputedStyle(e,t);if(!n.cssText)continue;const o=`.${a}:${t} {\n ${n.cssText}\n }`;s.appendChild(document.createTextNode(o)),r=!0}r&&(t.className=a,t.appendChild(s))}(e,t,n)),function(e){const t=["href","src"],n=window.location.href;for(const i of t){const t=e.getAttribute(i),r=(null==t?void 0:t.startsWith("http"))?void 0:t;if(r){const t=new URL(r,n).href;e.setAttribute(i,t)}}}(t),function(e,t){(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement)&&t.setAttribute("value",e.value)}(e,t),function(e){e instanceof SVGElement&&(e.setAttribute("xmlns","http://www.w3.org/2000/svg"),["width","height"].forEach((function(t){const n=e.getAttribute(t);n&&!e.style.getPropertyValue(t)&&e.style.setProperty(t,n)})))}(t),t):t}(t,d,n);return h}))},t.isSVGElement=l},136:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.tokenize=void 0;const n=String.fromCharCode;function i(e,t){return 0|e.charCodeAt(t)}function r(e,t){return t.push(e),e}let o=1,s=1,a=0,l=0,c=0,u="";function d(){return c=l<a?i(u,l++):0,s++,10===c&&(s=1,o++),c}function h(e,t){return function(e,t,n){return e.slice(t,n)}(u,e,t)}function f(e){switch(e){case 0:case 9:case 10:case 13:case 32:return 5;case 33:case 42:case 43:case 44:case 47:case 62:case 64:case 126:case 59:case 123:case 125:return 4;case 58:return 3;case 34:case 39:case 40:case 91:return 2;case 41:case 93:return 1}return 0}function g(e){return h(l-1,m(91===e?e+2:40===e?e+1:e)).trim()}function m(e){for(;d();)switch(c){case e:return l;case 34:case 39:34!==e&&39!==e&&m(c);break;case 40:41===e&&m(e);break;case 92:d()}return l}function p(e){for(;!f(i(u,l));)d();return h(e,l)}t.tokenize=function(e){return function(e){return u="",e}(function(e){for(;d();)switch(f(c)){case 0:r(p(l-1),e);break;case 2:r(g(c),e);break;default:r(n(c),e)}return e}(function(e){return o=s=1,a=function(e){return e.length}(u=e),l=0,[]}(e)))}},917:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.getInlinedNode=t.toSvg=t.toPng=t.toPixelData=t.toCanvas=t.toBlob=t.toJpeg=void 0;const r=n(110),o=n(32),s=n(663),a=n(261),l=n(787),c=n(69),u={inlineOptions:{}};function d(e,t){return i(this,void 0,void 0,(function*(){const{fonts:n,images:i,stylesheets:o,inlineImages:l}=t.inlineOptions||{};o&&(yield(0,c.inlineStylesheets)(t.fetchOptions));const u=getComputedStyle(document.documentElement),d=o?(0,c.cacheStylesheets)(u):void 0;let h=yield(0,r.cloneNode)(e,{styles:t.styles,filter:t.filter,root:!0,vector:!t.raster,fetchOptions:t.fetchOptions,getElementStyles:null==d?void 0:d.get,getPseudoElementStyles:null==d?void 0:d.getPseudo,images:i});if(h&&!(h instanceof Text))return n&&(h=yield function(e,t){return(0,s.resolveAll)(t).then((function(t){const n=document.createElement("style");return e.appendChild(n),n.appendChild(document.createTextNode(t)),e}))}(h,t.fetchOptions)),l&&(yield(0,a.inlineAllImages)(h,t.fetchOptions)),function(e){for(const t of e.querySelectorAll("*"))if(t instanceof HTMLElement&&!(0,r.isSVGElement)(t)){for(const e of Array.from(t.attributes))"class"===e.name&&t.className.includes("pseudo--")||g.includes(e.name)||t.removeAttribute(e.name);t instanceof HTMLAnchorElement&&(t.href=t.href.startsWith("http")?t.href:document.location.origin+t.href)}}(h),h}))}function h(e,t){return i(this,void 0,void 0,(function*(){t.inlineOptions=Object.assign({fonts:!0,images:!0,stylesheets:!0},t.inlineOptions);let n=yield d(e,t);if(n)return n=function(e,t){return t.backgroundColor&&(e.style.backgroundColor=t.backgroundColor),t.width&&(e.style.width=t.width+"px"),t.height&&(e.style.height=t.height+"px"),e}(n,t),function(e,t,n){e.setAttribute("xmlns","http://www.w3.org/1999/xhtml");return'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="'+t+'" height="'+n+'"><foreignObject x="0" y="0" width="100%" height="100%">'+(0,l.escapeXhtml)((new XMLSerializer).serializeToString(e))+"</foreignObject></svg>"}(n,t.width||(0,l.width)(e),t.height||(0,l.height)(e))}))}function f(e,t){return t=Object.assign(Object.assign({},u),t),h(e,t).then((e=>e?(0,o.createImage)(e,t.fetchOptions):null)).then((0,l.delay)(0)).then((function(n){const i="number"!=typeof t.scale?1:t.scale,r=function(e,t,n){const i=document.createElement("canvas");if(i.width=(n.width||(0,l.width)(e))*t,i.height=(n.height||(0,l.height)(e))*t,n.backgroundColor){const e=i.getContext("2d");if(!e)return null;e.fillStyle=n.backgroundColor,e.fillRect(0,0,i.width,i.height)}return i}(e,i,t),o=null==r?void 0:r.getContext("2d");return o?(o.imageSmoothingEnabled=!1,n&&(o.scale(i,i),o.drawImage(n,0,0)),r):null}))}t.getInlinedNode=d,t.toSvg=h,t.toPixelData=function(e,t){return(t=t||{}).raster=!0,f(e,t).then((function(t){var n;return null===(n=null==t?void 0:t.getContext("2d"))||void 0===n?void 0:n.getImageData(0,0,(0,l.width)(e),(0,l.height)(e)).data}))},t.toPng=function(e,t){return t.raster=!0,f(e,t).then((function(e){return null==e?void 0:e.toDataURL()}))},t.toJpeg=function(e,t){return t.raster=!0,f(e,t).then((function(e){return null==e?void 0:e.toDataURL("image/jpeg",t.quality||1)}))},t.toBlob=function(e,t){return t.raster=!0,f(e,t).then((e=>e&&(0,l.canvasToBlob)(e)))},t.toCanvas=function(e,t){return t.raster=!0,f(e,t)};const g=["src","href","title","style","srcset","sizes","width","height","target","rel"]},32:function(e,t){"use strict";var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};function i(e,t){if(!e.startsWith("http"))return e;if((null==t?void 0:t.noCache)&&(e+=(/\?/.test(e)?"&":"?")+Date.now()),(null==t?void 0:t.bypassCors)&&(null==t?void 0:t.corsHost)){if(e.startsWith(t.corsHost))return e;e=`${t.corsHost}/${e}`}return e}Object.defineProperty(t,"__esModule",{value:!0}),t.constructUrl=t.reloadImage=t.createImage=t.fetchResource=void 0,t.fetchResource=function(e,t){return n(this,void 0,void 0,(function*(){if(!e)return null;const n=yield fetch(i(e,t));if(!n.ok)return"";const r=yield n.blob(),o=new FileReader;return o.readAsDataURL(r),new Promise((e=>{o.addEventListener("loadend",(()=>{"string"==typeof o.result&&e(o.result)}))}))}))},t.createImage=function(e,t){return"data:,"===e?Promise.resolve(null):new Promise((function(n,r){const o=new Image;o.crossOrigin=(null==t?void 0:t.crossOrigin)||null,o.onload=function(){n(o)},o.onerror=r,o.src=i(e,t)}))},t.reloadImage=function(e,t){return t.corsHost&&e.currentSrc.startsWith(t.corsHost)?Promise.resolve(null):(t.noCache=!0,new Promise((function(n,r){e.crossOrigin=t.crossOrigin||null,e.onload=function(){n(e)},e.onerror=t=>{console.error("Failed to load image",e.currentSrc),r(t)},e.src=i(e.currentSrc,t)})))},t.constructUrl=i},663:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.resolveAll=void 0;const r=n(783);function o(e){return{resolve:function(t){const n=(e.parentStyleSheet||{}).href||void 0;return(0,r.inlineAll)(e.cssText,t,n)},src:function(){return e.style.getPropertyValue("src")}}}function s(e){return e.filter((function(e){return e.type===CSSRule.FONT_FACE_RULE})).filter((function(e){return(0,r.shouldProcess)(e.style.getPropertyValue("src"))}))}t.resolveAll=function(e){return i(this,void 0,void 0,(function*(){const t=s(function(e){const t=[];for(const n of e)try{const e=s(Array.from(n.cssRules));e.length>3&&t.push(e[0])}catch(e){e instanceof Error&&console.log("Error while reading CSS rules from "+n.href,e.toString())}return t}(document.styleSheets)).map(o),n=[];for(const i of t)n.push(yield i.resolve(e));return n.join("\n")}))}},261:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.inlineAllImages=void 0;const r=n(32),o=n(783),s=n(787);function a(e,t){return i(this,void 0,void 0,(function*(){if((0,s.isDataUrl)(e.currentSrc))return Promise.resolve(null);const n=yield(0,r.fetchResource)(e.currentSrc||e.src,t);return n?"data:,"===n?(e.removeAttribute("src"),e):new Promise((function(t,i){var r,o;"PICTURE"===(null===(r=e.parentElement)||void 0===r?void 0:r.tagName)&&(null===(o=e.parentElement)||void 0===o||o.replaceWith(e)),e.onload=()=>t(e),e.onerror=e=>i(e),e.src=n,e.removeAttribute("srcset")})):null}))}function l(e,t){return i(this,void 0,void 0,(function*(){const n=e.style.getPropertyValue("background-image");if(!n)return e;const i=yield(0,o.inlineAll)(n,t);return e.style.setProperty("background-image",i),e}))}t.inlineAllImages=function(e,t){return i(this,void 0,void 0,(function*(){const n=e.querySelectorAll("img"),i=[];for(let e=0;e<n.length;++e){const r=n[e];i.push(a(r,t))}const r=e.querySelectorAll('[style*="background-image:"],[style*="background:"]');for(let e=0;e<r.length;++e){const n=r[e];i.push(l(n,t))}yield Promise.all(i).catch((e=>console.error(e)))}))}},590:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.enterNodeSelectionMode=t.clipScreenshot=t.cleanup=t.clipArticle=t.clipPage=void 0;const r=n(107),o=n(787),s=n(482),a=n(917),l={nodeHover:"nn-node-selection--hover",nodeSelected:"nn-node-selection--selected",nodeSelectionContainer:"nn-node-selection-container"},c=[l.nodeSelected,l.nodeSelectionContainer],u={fonts:!1,images:!0,stylesheets:!0};function d(e){for(const t of c)if(e.classList.contains(t)||e.closest(`.${t}`))return!1;return!0}t.clipPage=function(e,t,n){return i(this,void 0,void 0,(function*(){const{body:i,head:r}=yield v(e,n,t);return i&&r?`<!doctype html>\n${p(r,i).documentElement.outerHTML}`:null}))},t.clipArticle=function(e,t){return i(this,void 0,void 0,(function*(){const{body:n,head:i}=yield v(e,t);if(!n||!i)return null;const o=p(i,n),s=new r.Readability(o);s.PRESENTATIONAL_ATTRIBUTES=["align","background","bgcolor","border","cellpadding","cellspacing","frame","hspace","rules","valign","vspace"];const a=s.parse();return`<!DOCTYPE html><html>${(null==i?void 0:i.outerHTML)||""}<body>${(null==a?void 0:a.content)||""}</body></html>`}))},t.clipScreenshot=function(e,t="jpeg",n){return i(this,void 0,void 0,(function*(){const i=e||document.body,r="jpeg"===t?a.toJpeg:"png"===t?a.toPng:a.toBlob,o=yield r(i,{quality:1,backgroundColor:"white",width:document.body.scrollWidth,height:document.body.scrollHeight,fetchOptions:b(n),inlineOptions:{fonts:!0,images:!0,stylesheets:!0},styles:!0});return"jpeg"===t||"png"===t?`<img width="${document.body.scrollWidth}px" height="${document.body.scrollHeight}px" src="${o}" />`:o}))};const h=e=>{const t=e.target;!t.classList.contains(l.nodeHover)&&d(t)&&t.classList.add(l.nodeHover)},f=e=>{const t=e.target;t.classList.contains(l.nodeHover)&&t.classList.remove(l.nodeHover)},g=e=>{e.preventDefault();const t=e.target;t.classList.contains(l.nodeSelected)?t.classList.remove(l.nodeSelected):d(t)&&t.classList.add(l.nodeSelected)};function m(e){e.nodeType!==Node.TEXT_NODE&&e.getBoundingClientRect||!e.parentElement||(e=e.parentElement);const t=function(e){const t={isInViewport:!1,isPartiallyInViewport:!1,isInsideViewport:!1,isAroundViewport:!1,isOnEdge:!1,isOnTopEdge:!1,isOnRightEdge:!1,isOnBottomEdge:!1,isOnLeftEdge:!1},n=e.getBoundingClientRect(),i=window.innerHeight||document.documentElement.clientHeight,r=window.innerWidth||document.documentElement.clientWidth,o=n.left>=0&&n.left+n.width<=r,s=n.top>=0&&n.top+n.height<=i;t.isInsideViewport=o&&s;const a=n.left<0&&n.left+n.width>r,l=n.top<0&&n.top+n.height>i;t.isAroundViewport=a&&l;const c=n.top<0&&n.top+n.height>0,u=n.left<r&&n.left+n.width>r,d=n.left<0&&n.left+n.width>0,h=n.top<i&&n.top+n.height>i,f=s||l||c||h,g=o||a||d||u;t.isOnTopEdge=c&&g,t.isOnRightEdge=u&&f,t.isOnBottomEdge=h&&g,t.isOnLeftEdge=d&&f,t.isOnEdge=t.isOnLeftEdge||t.isOnRightEdge||t.isOnTopEdge||t.isOnBottomEdge;const m=o||a||t.isOnLeftEdge||t.isOnRightEdge,p=s||l||t.isOnTopEdge||t.isOnBottomEdge;return t.isInViewport=m&&p,t.isPartiallyInViewport=t.isInViewport&&t.isOnEdge,t}(e);return t.isInViewport}function p(e,t){const n=document.implementation.createHTMLDocument();return n.documentElement.replaceChildren(e,t),n}function y(){setTimeout((()=>{var e;document.querySelectorAll(`.${l.nodeSelected}`).forEach((e=>{e instanceof HTMLElement&&e.classList.remove(l.nodeSelected)})),document.querySelectorAll(`.${l.nodeSelectionContainer}`).forEach((e=>e.remove())),(e=document).body.removeEventListener("mouseout",f),e.body.removeEventListener("mouseover",h),document.body.removeEventListener("click",g)}),0)}function v(e,t,n=!1){return i(this,void 0,void 0,(function*(){const i=yield(0,a.getInlinedNode)(e.body,{raster:!0,fetchOptions:b(t),inlineOptions:{fonts:!1,inlineImages:null==t?void 0:t.inlineImages,images:null==t?void 0:t.images,stylesheets:null==t?void 0:t.styles},styles:null==t?void 0:t.styles,filter:e=>!n||m(e)});if(!i)return{};const r=e.createElement("head"),o=e.createElement("title");return o.innerText=e.title,r.appendChild(o),{body:i,head:r}}))}function b(e){return(null==e?void 0:e.corsProxy)?{bypassCors:!0,corsHost:e.corsProxy,crossOrigin:"anonymous",noCache:!0}:void 0}t.enterNodeSelectionMode=function(e,t){return setTimeout((()=>{!function(e){e.body.addEventListener("click",g)}(e),function(e){e.body.addEventListener("mouseout",f),e.body.addEventListener("mouseover",h)}(e)}),0),function(){const e=`.${l.nodeHover} {\n border: 1px solid green;\n background-color: rgb(0,0,0,0.05);\n cursor: pointer;\n }\n\n .${l.nodeSelected} {\n border: 2px solid green;\n cursor: pointer;\n }\n\n .${l.nodeSelectionContainer} {\n position: fixed;\n bottom: 0px;\n right: 0px;\n z-index: ${Number.MAX_VALUE};\n }`;(0,o.injectCss)(e,"nn-clipper-styles")}(),new Promise(((e,n)=>{!function(e,t){const n=document.createElement("div");n.classList.add(l.nodeSelectionContainer),setTimeout((()=>{document.body.appendChild(n)}),0),(0,s.app)({init:{isClipping:!1},view:({isClipping:n})=>(0,s.h)("div",{style:{padding:"10px",backgroundColor:"white",borderRadius:"5px",boxShadow:"0px 0px 10px 0px #00000038"}},[(0,s.h)("p",{style:{marginBottom:"0px",fontSize:"18px"}},[(0,s.text)("Notesnook Web Clipper")]),(0,s.h)("p",{style:{margin:"0px",marginBottom:"5px",fontStyle:"italic"}},[n?(0,s.text)("Clipping selected elements. Please wait..."):(0,s.text)("Click on any element to select it.")]),(0,s.h)("div",{style:{display:"flex",alignItems:"center"}},[(0,s.h)("button",{onclick:t=>[Object.assign(Object.assign({},t),{isClipping:!0}),t=>{null==e||e(),t({isClipping:!1})}],style:{marginRight:"5px"},disabled:n},[n?(0,s.text)("Clipping..."):(0,s.text)("Clip")]),(0,s.h)("button",{onclick:e=>(y(),null==t||t(),e),disabled:n},[(0,s.text)("Cancel")])])]),node:n})}((()=>i(this,void 0,void 0,(function*(){y();const n=document.querySelectorAll(`.${l.nodeSelected}`),i=document.createElement("div");for(const e of n){e.classList.remove(l.nodeSelected);const n=yield(0,a.getInlinedNode)(e,{raster:!1,fetchOptions:b(t),inlineOptions:u});n&&i.appendChild(n)}e(null==i?void 0:i.outerHTML)}))),(()=>n("Cancelled.")))}))},t.cleanup=y},783:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.readUrls=t.inlineAll=t.shouldProcess=void 0;const r=n(32),o=n(787),s=/url\(['"]?([^'"]+?)['"]?\)/g;function a(e){return-1!==e.search(s)}function l(e){const t=[];let n;for(;null!==(n=s.exec(e));)t.push(n[1]);return t.filter((function(e){return!(0,o.isDataUrl)(e)}))}function c(e,t,n,s){return i(this,void 0,void 0,(function*(){t=s?(0,o.resolveUrl)(t,s):t;const i=yield(0,r.fetchResource)(t,n);return e.replace((a=t,new RegExp("(url\\(['\"]?)("+(0,o.escape)(a)+")(['\"]?\\))","g")),"$1"+i+"$3");var a}))}t.shouldProcess=a,t.readUrls=l,t.inlineAll=function(e,t,n){return i(this,void 0,void 0,(function*(){if(!a(e))return e;const i=l(e);let r=e;for(const e of i)r=yield c(r,e,t,n);return r}))}},69:function(e,t,n){"use strict";var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}l((i=i.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.cacheStylesheets=t.inlineStylesheets=void 0;const r=n(32),o=n(302),s=n(136),a=n(763),l=["animation","background","border","border-block-end","border-block-start","border-bottom","border-color","border-image","border-inline-end","border-inline-start","border-left","border-radius","border-right","border-style","border-top","border-width","column-rule","columns","contain-intrinsic-size","flex","flex-flow","font","gap","grid","grid-area","grid-column","grid-row","grid-template","grid-gap","list-style","margin","mask","offset","outline","overflow","padding","place-content","place-items","place-self","scroll-margin","scroll-padding","text-decoration","text-emphasis","transition"];function c(e,t){return i(this,void 0,void 0,(function*(){try{const n=document.createElement("style"),i=yield fetch((0,r.constructUrl)(e,t));return!!i.ok&&(n.innerText=yield i.text(),n.setAttribute("href",e),n)}catch(t){console.error("Failed to inline stylesheet",e,t)}}))}function u(e,t,n,i,r){for(const a of e)if(a instanceof CSSStyleRule){if((s=a.selectorText).includes(":before")||s.includes(":after")||s.includes("::after")||s.includes("::before")){const e=p(a.selectorText);for(const t of e){if(!t||!t.selector.trim())continue;const e=document.querySelectorAll(t.selector);for(const n of e){if(!(n instanceof HTMLElement||n instanceof SVGElement))continue;const e=i.get(n)||[];i.set(n,e),e.push({rule:a.style,href:m(r),pseudoElement:t.pseudoElement})}}}const e=document.querySelectorAll(a.selectorText);for(const t of e){if(!(t instanceof HTMLElement||t instanceof SVGElement))continue;const e=a.selectorText.split(","),i=n.get(t)||[];n.set(t,i);for(const t of e)try{const e=(0,o.calculate)(t)[0];i.push({specificity:e.specificityArray,rule:a.style,href:m(r)});break}catch(e){console.error(e,r&&m(r))}}}else(a instanceof CSSMediaRule&&window.matchMedia(a.conditionText).matches||a instanceof CSSSupportsRule&&CSS.supports(a.conditionText))&&u(a.cssRules,t,n,i,r);var s}function d(e,t,n){const i=function(){const e=new CSSStyleSheet;return e.insertRule(".dummy{}"),e.cssRules[0].style}(),r=function(e){let t;return Object.defineProperty({},"style",{get:()=>(t||(t=getComputedStyle(e)),t)})}(e),o=["display"];for(const e of t)for(const t of[...e.rule,...l]){let s=e.rule.getPropertyValue(t);o.includes(t)&&(s=r.style.getPropertyValue(t)),s.trim()&&h(i,t,s,(e=>r.style.getPropertyValue(e)||n.getPropertyValue(e)),(t=>(console.log("resolving url",t,e.href),t.startsWith("data:")||!e.href?t:(console.log("resolving url",t,e.href.href),t.startsWith("/")?new URL(`${e.href.origin}${t}`).href:new URL(`${e.href.href}${t}`).href))),e.rule.getPropertyPriority(t))}return i}function h(e,t,n,i,r,o){n=function(e,t){const n=(0,s.tokenize)(e),i=[];for(let e=0;e<n.length;++e){const r=n[e];if("url"!==r||n[e+1].startsWith("(data"))i.push(r);else{const o=t(n[++e].slice(2,-2));o&&(i.push(r),i.push('("'),i.push(o),i.push('")'))}}return i.join("")}(n=g(n,i),r),e.setProperty(t,n,o)}function f(e){return e.media.mediaText.split(",").map((e=>e.trim())).includes("print")}function g(e,t){const n=(0,s.tokenize)(e),i=[];for(let e=0;e<n.length;++e){const r=n[e];if("var"===r){const r=(0,s.tokenize)(n[++e].slice(1,-1)),[o,a,l,...c]=r,u=t(o);u?i.push(u):a&&c.length<=1?i.push(c[0]||l):a&&2===c.length&&i.push(g(c.join(""),t))}else r.startsWith("(")&&r.endsWith(")")?i.push("(",g(r.slice(1,-1),t),")"):i.push(r)}return i.join("")}function m(e){if(!e)return null;e.startsWith("/")&&(e=`${document.location.origin}${e}`);const t=new URL(e),n=t.pathname.split("/").slice(0,-1).join("/");return new URL(`${t.origin}${n}/`)}function p(e){const t=[],n=(0,a.parse)(e);for(const e of n){const n=e.findIndex((e=>!(e.type!==a.SelectorType.Pseudo&&e.type!==a.SelectorType.PseudoElement||"after"!==e.name&&"before"!==e.name)));n<=-1||t.push({selector:(0,a.stringify)([e.slice(0,n)]),pseudoElement:(0,a.stringify)([e.slice(n)])})}return t}t.inlineStylesheets=function(e){return i(this,void 0,void 0,(function*(){for(const t of document.styleSheets){if(f(t))continue;const n=t.ownerNode;if(t.href&&n instanceof HTMLLinkElement)try{t.cssRules.length}catch(t){const i=yield c(n.href,e);i&&n.replaceWith(i),console.error("Failed to access sheet",n.href,t)}}yield function(e){return i(this,void 0,void 0,(function*(){for(const t of document.styleSheets){const n=[];if(!f(t)){for(let i=0;i<t.cssRules.length;++i){const r=t.cssRules.item(i);if(r&&r.type===CSSRule.IMPORT_RULE){const o=r.href,s=yield c(o,e);s&&(t.ownerNode?t.ownerNode.before(s):document.head.appendChild(s),n.push(i))}}for(const e of n)t.deleteRule(e)}}}))}(e)}))},t.cacheStylesheets=function(e){const t=new Map,n=new Map;for(const i of document.styleSheets){if(f(i))continue;let r=i.href||void 0;!r&&i.ownerNode instanceof HTMLElement&&(r=i.ownerNode.getAttribute("href")||void 0),u(i.cssRules,e,t,n,r)}return{getPseudo(t,i){var r;const o=null===(r=n.get(t))||void 0===r?void 0:r.filter((e=>e.pseudoElement.includes(i)));if(o&&o.length)return d(t,o,e)},get(n){const i=t.get(n);if(!i)return;const r=i.sort(((e,t)=>(0,o.compare)(e.specificity,t.specificity)));return r.push({rule:n.style,specificity:[0,0,0,0],href:null}),d(n,r,e)}}}},787:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.height=t.width=t.escapeXhtml=t.asArray=t.delay=t.uid=t.resolveUrl=t.canvasToBlob=t.isDataUrl=t.dataAsUrl=t.mimeType=t.parseExtension=t.escape=t.injectCss=void 0;const n="application/font-woff",i="image/jpeg",r={woff:n,woff2:n,ttf:"application/font-truetype",eot:"application/vnd.ms-fontobject",png:"image/png",jpg:i,jpeg:i,gif:"image/gif",tiff:"image/tiff",svg:"image/svg+xml"};function o(e){const t=/\.([^./]*?)(\?|$)/g.exec(e);return t?t[1]:""}t.parseExtension=o,t.mimeType=function(e){const t=o(e).toLowerCase();return r[t]||""},t.isDataUrl=function(e){return-1!==e.search(/^(data:)/)},t.canvasToBlob=function(e){return e.toBlob?new Promise((function(t){e.toBlob(t)})):Promise.resolve(function(e){const t=atob(e.toDataURL().split(",")[1]),n=t.length,i=new Uint8Array(n);for(let e=0;e<n;e++)i[e]=t.charCodeAt(e);return new Blob([i],{type:"image/png"})}(e))},t.resolveUrl=function(e,t){const n=document.implementation.createHTMLDocument(),i=n.createElement("base");n.head.appendChild(i);const r=n.createElement("a");return n.body.appendChild(r),i.href=t,r.href=e,r.href};let s=0;function a(e,t){const n=getComputedStyle(e).getPropertyValue(t);return parseFloat(n.replace("px",""))}t.uid=function(){return"u"+("0000"+(Math.random()*Math.pow(36,4)<<0).toString(36)).slice(-4)+s++},t.dataAsUrl=function(e,t){return"data:"+t+";base64,"+e},t.escape=function(e){return e.replace(/([.*+?^${}()|[\]/\\])/g,"\\$1")},t.delay=function(e){return function(t){return new Promise((function(n){setTimeout((function(){n(t)}),e)}))}},t.asArray=function(e){const t=[],n=e.length;for(let i=0;i<n;i++)t.push(e[i]);return t},t.escapeXhtml=function(e){return e.replace(/%/g,"%25").replace(/#/g,"%23").replace(/\n/g,"%0A")},t.width=function(e){const t=a(e,"border-left-width"),n=a(e,"border-right-width");return e.scrollWidth+t+n},t.height=function(e){const t=a(e,"border-top-width"),n=a(e,"border-bottom-width");return e.scrollHeight+t+n},t.injectCss=function(e,t){const n=document.getElementById(t),i=document.getElementsByTagName("head")[0];n&&i.removeChild(n);const r=document.createElement("style");r.type="text/css",r.id=t,r.appendChild(document.createTextNode(e)),i.insertBefore(r,function(){for(const e of document.querySelectorAll("style"))if(e.innerHTML.includes("#root"))return e;return null}())}},893:e=>{var t={unlikelyCandidates:/-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,okMaybeItsACandidate:/and|article|body|column|content|main|shadow/i};function n(e){return(!e.style||"none"!=e.style.display)&&!e.hasAttribute("hidden")&&(!e.hasAttribute("aria-hidden")||"true"!=e.getAttribute("aria-hidden")||e.className&&e.className.indexOf&&-1!==e.className.indexOf("fallback-image"))}e.exports=function(e,i={}){"function"==typeof i&&(i={visibilityChecker:i});var r={minScore:20,minContentLength:140,visibilityChecker:n};i=Object.assign(r,i);var o=e.querySelectorAll("p, pre, article"),s=e.querySelectorAll("div > br");if(s.length){var a=new Set(o);[].forEach.call(s,(function(e){a.add(e.parentNode)})),o=Array.from(a)}var l=0;return[].some.call(o,(function(e){if(!i.visibilityChecker(e))return!1;var n=e.className+" "+e.id;if(t.unlikelyCandidates.test(n)&&!t.okMaybeItsACandidate.test(n))return!1;if(e.matches("li p"))return!1;var r=e.textContent.trim().length;return!(r<i.minContentLength)&&(l+=Math.sqrt(r-i.minContentLength))>i.minScore}))}},174:e=>{function t(e,t){if(t&&t.documentElement)e=t,t=arguments[2];else if(!e||!e.documentElement)throw new Error("First argument to Readability constructor should be a document object.");if(t=t||{},this._doc=e,this._docJSDOMParser=this._doc.firstChild.__JSDOMParser__,this._articleTitle=null,this._articleByline=null,this._articleDir=null,this._articleSiteName=null,this._attempts=[],this._debug=!!t.debug,this._maxElemsToParse=t.maxElemsToParse||this.DEFAULT_MAX_ELEMS_TO_PARSE,this._nbTopCandidates=t.nbTopCandidates||this.DEFAULT_N_TOP_CANDIDATES,this._charThreshold=t.charThreshold||this.DEFAULT_CHAR_THRESHOLD,this._classesToPreserve=this.CLASSES_TO_PRESERVE.concat(t.classesToPreserve||[]),this._keepClasses=!!t.keepClasses,this._serializer=t.serializer||function(e){return e.innerHTML},this._disableJSONLD=!!t.disableJSONLD,this._flags=this.FLAG_STRIP_UNLIKELYS|this.FLAG_WEIGHT_CLASSES|this.FLAG_CLEAN_CONDITIONALLY,this._debug){let e=function(e){if(e.nodeType==e.TEXT_NODE)return`${e.nodeName} ("${e.textContent}")`;let t=Array.from(e.attributes||[],(function(e){return`${e.name}="${e.value}"`})).join(" ");return`<${e.localName} ${t}>`};this.log=function(){if("undefined"!=typeof dump){var t=Array.prototype.map.call(arguments,(function(t){return t&&t.nodeName?e(t):t})).join(" ");dump("Reader: (Readability) "+t+"\n")}else if("undefined"!=typeof console){let t=Array.from(arguments,(t=>t&&t.nodeType==this.ELEMENT_NODE?e(t):t));t.unshift("Reader: (Readability)"),console.log.apply(console,t)}}}else this.log=function(){}}t.prototype={FLAG_STRIP_UNLIKELYS:1,FLAG_WEIGHT_CLASSES:2,FLAG_CLEAN_CONDITIONALLY:4,ELEMENT_NODE:1,TEXT_NODE:3,DEFAULT_MAX_ELEMS_TO_PARSE:0,DEFAULT_N_TOP_CANDIDATES:5,DEFAULT_TAGS_TO_SCORE:"section,h2,h3,h4,h5,h6,p,td,pre".toUpperCase().split(","),DEFAULT_CHAR_THRESHOLD:500,REGEXPS:{unlikelyCandidates:/-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,okMaybeItsACandidate:/and|article|body|column|content|main|shadow/i,positive:/article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i,negative:/-ad-|hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,extraneous:/print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,byline:/byline|author|dateline|writtenby|p-author/i,replaceFonts:/<(\/?)font[^>]*>/gi,normalize:/\s{2,}/g,videos:/\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i,shareElements:/(\b|_)(share|sharedaddy)(\b|_)/i,nextLink:/(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i,prevLink:/(prev|earl|old|new|<|«)/i,tokenize:/\W+/g,whitespace:/^\s*$/,hasContent:/\S$/,hashUrl:/^#.+/,srcsetUrl:/(\S+)(\s+[\d.]+[xw])?(\s*(?:,|$))/g,b64DataUrl:/^data:\s*([^\s;,]+)\s*;\s*base64\s*,/i,jsonLdArticleTypes:/^Article|AdvertiserContentArticle|NewsArticle|AnalysisNewsArticle|AskPublicNewsArticle|BackgroundNewsArticle|OpinionNewsArticle|ReportageNewsArticle|ReviewNewsArticle|Report|SatiricalArticle|ScholarlyArticle|MedicalScholarlyArticle|SocialMediaPosting|BlogPosting|LiveBlogPosting|DiscussionForumPosting|TechArticle|APIReference$/},UNLIKELY_ROLES:["menu","menubar","complementary","navigation","alert","alertdialog","dialog"],DIV_TO_P_ELEMS:new Set(["BLOCKQUOTE","DL","DIV","IMG","OL","P","PRE","TABLE","UL"]),ALTER_TO_DIV_EXCEPTIONS:["DIV","ARTICLE","SECTION","P"],PRESENTATIONAL_ATTRIBUTES:["align","background","bgcolor","border","cellpadding","cellspacing","frame","hspace","rules","style","valign","vspace"],DEPRECATED_SIZE_ATTRIBUTE_ELEMS:["TABLE","TH","TD","HR","PRE"],PHRASING_ELEMS:["ABBR","AUDIO","B","BDO","BR","BUTTON","CITE","CODE","DATA","DATALIST","DFN","EM","EMBED","I","IMG","INPUT","KBD","LABEL","MARK","MATH","METER","NOSCRIPT","OBJECT","OUTPUT","PROGRESS","Q","RUBY","SAMP","SCRIPT","SELECT","SMALL","SPAN","STRONG","SUB","SUP","TEXTAREA","TIME","VAR","WBR"],CLASSES_TO_PRESERVE:["page"],HTML_ESCAPE_MAP:{lt:"<",gt:">",amp:"&",quot:'"',apos:"'"},_postProcessContent:function(e){this._fixRelativeUris(e),this._simplifyNestedElements(e),this._keepClasses||this._cleanClasses(e)},_removeNodes:function(e,t){if(this._docJSDOMParser&&e._isLiveNodeList)throw new Error("Do not pass live node lists to _removeNodes");for(var n=e.length-1;n>=0;n--){var i=e[n],r=i.parentNode;r&&(t&&!t.call(this,i,n,e)||r.removeChild(i))}},_replaceNodeTags:function(e,t){if(this._docJSDOMParser&&e._isLiveNodeList)throw new Error("Do not pass live node lists to _replaceNodeTags");for(const n of e)this._setNodeTag(n,t)},_forEachNode:function(e,t){Array.prototype.forEach.call(e,t,this)},_findNode:function(e,t){return Array.prototype.find.call(e,t,this)},_someNode:function(e,t){return Array.prototype.some.call(e,t,this)},_everyNode:function(e,t){return Array.prototype.every.call(e,t,this)},_concatNodeLists:function(){var e=Array.prototype.slice,t=e.call(arguments).map((function(t){return e.call(t)}));return Array.prototype.concat.apply([],t)},_getAllNodesWithTag:function(e,t){return e.querySelectorAll?e.querySelectorAll(t.join(",")):[].concat.apply([],t.map((function(t){var n=e.getElementsByTagName(t);return Array.isArray(n)?n:Array.from(n)})))},_cleanClasses:function(e){var t=this._classesToPreserve,n=(e.getAttribute("class")||"").split(/\s+/).filter((function(e){return-1!=t.indexOf(e)})).join(" ");for(n?e.setAttribute("class",n):e.removeAttribute("class"),e=e.firstElementChild;e;e=e.nextElementSibling)this._cleanClasses(e)},_fixRelativeUris:function(e){var t=this._doc.baseURI,n=this._doc.documentURI;function i(e){if(t==n&&"#"==e.charAt(0))return e;try{return new URL(e,t).href}catch(e){}return e}var r=this._getAllNodesWithTag(e,["a"]);this._forEachNode(r,(function(e){var t=e.getAttribute("href");if(t)if(0===t.indexOf("javascript:"))if(1===e.childNodes.length&&e.childNodes[0].nodeType===this.TEXT_NODE){var n=this._doc.createTextNode(e.textContent);e.parentNode.replaceChild(n,e)}else{for(var r=this._doc.createElement("span");e.firstChild;)r.appendChild(e.firstChild);e.parentNode.replaceChild(r,e)}else e.setAttribute("href",i(t))}));var o=this._getAllNodesWithTag(e,["img","picture","figure","video","audio","source"]);this._forEachNode(o,(function(e){var t=e.getAttribute("src"),n=e.getAttribute("poster"),r=e.getAttribute("srcset");if(t&&e.setAttribute("src",i(t)),n&&e.setAttribute("poster",i(n)),r){var o=r.replace(this.REGEXPS.srcsetUrl,(function(e,t,n,r){return i(t)+(n||"")+r}));e.setAttribute("srcset",o)}}))},_simplifyNestedElements:function(e){for(var t=e;t;){if(t.parentNode&&["DIV","SECTION"].includes(t.tagName)&&(!t.id||!t.id.startsWith("readability"))){if(this._isElementWithoutContent(t)){t=this._removeAndGetNext(t);continue}if(this._hasSingleTagInsideElement(t,"DIV")||this._hasSingleTagInsideElement(t,"SECTION")){for(var n=t.children[0],i=0;i<t.attributes.length;i++)n.setAttribute(t.attributes[i].name,t.attributes[i].value);t.parentNode.replaceChild(n,t),t=n;continue}}t=this._getNextNode(t)}},_getArticleTitle:function(){var e=this._doc,t="",n="";try{"string"!=typeof(t=n=e.title.trim())&&(t=n=this._getInnerText(e.getElementsByTagName("title")[0]))}catch(e){}var i=!1;function r(e){return e.split(/\s+/).length}if(/ [\|\-\\\/>»] /.test(t))i=/ [\\\/>»] /.test(t),r(t=n.replace(/(.*)[\|\-\\\/>»] .*/gi,"$1"))<3&&(t=n.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi,"$1"));else if(-1!==t.indexOf(": ")){var o=this._concatNodeLists(e.getElementsByTagName("h1"),e.getElementsByTagName("h2")),s=t.trim();this._someNode(o,(function(e){return e.textContent.trim()===s}))||(r(t=n.substring(n.lastIndexOf(":")+1))<3?t=n.substring(n.indexOf(":")+1):r(n.substr(0,n.indexOf(":")))>5&&(t=n))}else if(t.length>150||t.length<15){var a=e.getElementsByTagName("h1");1===a.length&&(t=this._getInnerText(a[0]))}var l=r(t=t.trim().replace(this.REGEXPS.normalize," "));return l<=4&&(!i||l!=r(n.replace(/[\|\-\\\/>»]+/g,""))-1)&&(t=n),t},_prepDocument:function(){var e=this._doc;this._removeNodes(this._getAllNodesWithTag(e,["style"])),e.body&&this._replaceBrs(e.body),this._replaceNodeTags(this._getAllNodesWithTag(e,["font"]),"SPAN")},_nextNode:function(e){for(var t=e;t&&t.nodeType!=this.ELEMENT_NODE&&this.REGEXPS.whitespace.test(t.textContent);)t=t.nextSibling;return t},_replaceBrs:function(e){this._forEachNode(this._getAllNodesWithTag(e,["br"]),(function(e){for(var t=e.nextSibling,n=!1;(t=this._nextNode(t))&&"BR"==t.tagName;){n=!0;var i=t.nextSibling;t.parentNode.removeChild(t),t=i}if(n){var r=this._doc.createElement("p");for(e.parentNode.replaceChild(r,e),t=r.nextSibling;t;){if("BR"==t.tagName){var o=this._nextNode(t.nextSibling);if(o&&"BR"==o.tagName)break}if(!this._isPhrasingContent(t))break;var s=t.nextSibling;r.appendChild(t),t=s}for(;r.lastChild&&this._isWhitespace(r.lastChild);)r.removeChild(r.lastChild);"P"===r.parentNode.tagName&&this._setNodeTag(r.parentNode,"DIV")}}))},_setNodeTag:function(e,t){if(this.log("_setNodeTag",e,t),this._docJSDOMParser)return e.localName=t.toLowerCase(),e.tagName=t.toUpperCase(),e;for(var n=e.ownerDocument.createElement(t);e.firstChild;)n.appendChild(e.firstChild);e.parentNode.replaceChild(n,e),e.readability&&(n.readability=e.readability);for(var i=0;i<e.attributes.length;i++)try{n.setAttribute(e.attributes[i].name,e.attributes[i].value)}catch(e){}return n},_prepArticle:function(e){this._cleanStyles(e),this._markDataTables(e),this._fixLazyImages(e),this._cleanConditionally(e,"form"),this._cleanConditionally(e,"fieldset"),this._clean(e,"object"),this._clean(e,"embed"),this._clean(e,"footer"),this._clean(e,"link"),this._clean(e,"aside");var t=this.DEFAULT_CHAR_THRESHOLD;this._forEachNode(e.children,(function(e){this._cleanMatchedNodes(e,(function(e,n){return this.REGEXPS.shareElements.test(n)&&e.textContent.length<t}))})),this._clean(e,"iframe"),this._clean(e,"input"),this._clean(e,"textarea"),this._clean(e,"select"),this._clean(e,"button"),this._cleanHeaders(e),this._cleanConditionally(e,"table"),this._cleanConditionally(e,"ul"),this._cleanConditionally(e,"div"),this._replaceNodeTags(this._getAllNodesWithTag(e,["h1"]),"h2"),this._removeNodes(this._getAllNodesWithTag(e,["p"]),(function(e){return 0===e.getElementsByTagName("img").length+e.getElementsByTagName("embed").length+e.getElementsByTagName("object").length+e.getElementsByTagName("iframe").length&&!this._getInnerText(e,!1)})),this._forEachNode(this._getAllNodesWithTag(e,["br"]),(function(e){var t=this._nextNode(e.nextSibling);t&&"P"==t.tagName&&e.parentNode.removeChild(e)})),this._forEachNode(this._getAllNodesWithTag(e,["table"]),(function(e){var t=this._hasSingleTagInsideElement(e,"TBODY")?e.firstElementChild:e;if(this._hasSingleTagInsideElement(t,"TR")){var n=t.firstElementChild;if(this._hasSingleTagInsideElement(n,"TD")){var i=n.firstElementChild;i=this._setNodeTag(i,this._everyNode(i.childNodes,this._isPhrasingContent)?"P":"DIV"),e.parentNode.replaceChild(i,e)}}}))},_initializeNode:function(e){switch(e.readability={contentScore:0},e.tagName){case"DIV":e.readability.contentScore+=5;break;case"PRE":case"TD":case"BLOCKQUOTE":e.readability.contentScore+=3;break;case"ADDRESS":case"OL":case"UL":case"DL":case"DD":case"DT":case"LI":case"FORM":e.readability.contentScore-=3;break;case"H1":case"H2":case"H3":case"H4":case"H5":case"H6":case"TH":e.readability.contentScore-=5}e.readability.contentScore+=this._getClassWeight(e)},_removeAndGetNext:function(e){var t=this._getNextNode(e,!0);return e.parentNode.removeChild(e),t},_getNextNode:function(e,t){if(!t&&e.firstElementChild)return e.firstElementChild;if(e.nextElementSibling)return e.nextElementSibling;do{e=e.parentNode}while(e&&!e.nextElementSibling);return e&&e.nextElementSibling},_textSimilarity:function(e,t){var n=e.toLowerCase().split(this.REGEXPS.tokenize).filter(Boolean),i=t.toLowerCase().split(this.REGEXPS.tokenize).filter(Boolean);return n.length&&i.length?1-i.filter((e=>!n.includes(e))).join(" ").length/i.join(" ").length:0},_checkByline:function(e,t){if(this._articleByline)return!1;if(void 0!==e.getAttribute)var n=e.getAttribute("rel"),i=e.getAttribute("itemprop");return!(!("author"===n||i&&-1!==i.indexOf("author")||this.REGEXPS.byline.test(t))||!this._isValidByline(e.textContent)||(this._articleByline=e.textContent.trim(),0))},_getNodeAncestors:function(e,t){t=t||0;for(var n=0,i=[];e.parentNode&&(i.push(e.parentNode),!t||++n!==t);)e=e.parentNode;return i},_grabArticle:function(e){this.log("**** grabArticle ****");var t=this._doc,n=null!==e;if(!(e=e||this._doc.body))return this.log("No body found in document. Abort."),null;for(var i=e.innerHTML;;){this.log("Starting grabArticle loop");var r=this._flagIsActive(this.FLAG_STRIP_UNLIKELYS),o=[],s=this._doc.documentElement;let F=!0;for(;s;){"HTML"===s.tagName&&(this._articleLang=s.getAttribute("lang"));var a=s.className+" "+s.id;if(this._isProbablyVisible(s))if(this._checkByline(s,a))s=this._removeAndGetNext(s);else if(F&&this._headerDuplicatesTitle(s))this.log("Removing header: ",s.textContent.trim(),this._articleTitle.trim()),F=!1,s=this._removeAndGetNext(s);else{if(r){if(this.REGEXPS.unlikelyCandidates.test(a)&&!this.REGEXPS.okMaybeItsACandidate.test(a)&&!this._hasAncestorTag(s,"table")&&!this._hasAncestorTag(s,"code")&&"BODY"!==s.tagName&&"A"!==s.tagName){this.log("Removing unlikely candidate - "+a),s=this._removeAndGetNext(s);continue}if(this.UNLIKELY_ROLES.includes(s.getAttribute("role"))){this.log("Removing content with role "+s.getAttribute("role")+" - "+a),s=this._removeAndGetNext(s);continue}}if("DIV"!==s.tagName&&"SECTION"!==s.tagName&&"HEADER"!==s.tagName&&"H1"!==s.tagName&&"H2"!==s.tagName&&"H3"!==s.tagName&&"H4"!==s.tagName&&"H5"!==s.tagName&&"H6"!==s.tagName||!this._isElementWithoutContent(s)){if(-1!==this.DEFAULT_TAGS_TO_SCORE.indexOf(s.tagName)&&o.push(s),"DIV"===s.tagName){for(var l=null,c=s.firstChild;c;){var u=c.nextSibling;if(this._isPhrasingContent(c))null!==l?l.appendChild(c):this._isWhitespace(c)||(l=t.createElement("p"),s.replaceChild(l,c),l.appendChild(c));else if(null!==l){for(;l.lastChild&&this._isWhitespace(l.lastChild);)l.removeChild(l.lastChild);l=null}c=u}if(this._hasSingleTagInsideElement(s,"P")&&this._getLinkDensity(s)<.25){var d=s.children[0];s.parentNode.replaceChild(d,s),s=d,o.push(s)}else this._hasChildBlockElement(s)||(s=this._setNodeTag(s,"P"),o.push(s))}s=this._getNextNode(s)}else s=this._removeAndGetNext(s)}else this.log("Removing hidden node - "+a),s=this._removeAndGetNext(s)}var h=[];this._forEachNode(o,(function(e){if(e.parentNode&&void 0!==e.parentNode.tagName){var t=this._getInnerText(e);if(!(t.length<25)){var n=this._getNodeAncestors(e,5);if(0!==n.length){var i=0;i+=1,i+=t.split(",").length,i+=Math.min(Math.floor(t.length/100),3),this._forEachNode(n,(function(e,t){if(e.tagName&&e.parentNode&&void 0!==e.parentNode.tagName){if(void 0===e.readability&&(this._initializeNode(e),h.push(e)),0===t)var n=1;else n=1===t?2:3*t;e.readability.contentScore+=i/n}}))}}}}));for(var f=[],g=0,m=h.length;g<m;g+=1){var p=h[g],y=p.readability.contentScore*(1-this._getLinkDensity(p));p.readability.contentScore=y,this.log("Candidate:",p,"with score "+y);for(var v=0;v<this._nbTopCandidates;v++){var b=f[v];if(!b||y>b.readability.contentScore){f.splice(v,0,p),f.length>this._nbTopCandidates&&f.pop();break}}}var _,E=f[0]||null,N=!1;if(null===E||"BODY"===E.tagName){for(E=t.createElement("DIV"),N=!0;e.firstChild;)this.log("Moving child out:",e.firstChild),E.appendChild(e.firstChild);e.appendChild(E),this._initializeNode(E)}else if(E){for(var A=[],T=1;T<f.length;T++)f[T].readability.contentScore/E.readability.contentScore>=.75&&A.push(this._getNodeAncestors(f[T]));if(A.length>=3)for(_=E.parentNode;"BODY"!==_.tagName;){for(var C=0,S=0;S<A.length&&C<3;S++)C+=Number(A[S].includes(_));if(C>=3){E=_;break}_=_.parentNode}E.readability||this._initializeNode(E),_=E.parentNode;for(var w=E.readability.contentScore,x=w/3;"BODY"!==_.tagName;)if(_.readability){var L=_.readability.contentScore;if(L<x)break;if(L>w){E=_;break}w=_.readability.contentScore,_=_.parentNode}else _=_.parentNode;for(_=E.parentNode;"BODY"!=_.tagName&&1==_.children.length;)_=(E=_).parentNode;E.readability||this._initializeNode(E)}var P=t.createElement("DIV");n&&(P.id="readability-content");for(var O=Math.max(10,.2*E.readability.contentScore),I=(_=E.parentNode).children,R=0,D=I.length;R<D;R++){var M=I[R],k=!1;if(this.log("Looking at sibling node:",M,M.readability?"with score "+M.readability.contentScore:""),this.log("Sibling has score",M.readability?M.readability.contentScore:"Unknown"),M===E)k=!0;else{var B=0;if(M.className===E.className&&""!==E.className&&(B+=.2*E.readability.contentScore),M.readability&&M.readability.contentScore+B>=O)k=!0;else if("P"===M.nodeName){var H=this._getLinkDensity(M),U=this._getInnerText(M),j=U.length;(j>80&&H<.25||j<80&&j>0&&0===H&&-1!==U.search(/\.( |$)/))&&(k=!0)}}k&&(this.log("Appending node:",M),-1===this.ALTER_TO_DIV_EXCEPTIONS.indexOf(M.nodeName)&&(this.log("Altering sibling:",M,"to div."),M=this._setNodeTag(M,"DIV")),P.appendChild(M),I=_.children,R-=1,D-=1)}if(this._debug&&this.log("Article content pre-prep: "+P.innerHTML),this._prepArticle(P),this._debug&&this.log("Article content post-prep: "+P.innerHTML),N)E.id="readability-page-1",E.className="page";else{var $=t.createElement("DIV");for($.id="readability-page-1",$.className="page";P.firstChild;)$.appendChild(P.firstChild);P.appendChild($)}this._debug&&this.log("Article content after paging: "+P.innerHTML);var G=!0,V=this._getInnerText(P,!0).length;if(V<this._charThreshold)if(G=!1,e.innerHTML=i,this._flagIsActive(this.FLAG_STRIP_UNLIKELYS))this._removeFlag(this.FLAG_STRIP_UNLIKELYS),this._attempts.push({articleContent:P,textLength:V});else if(this._flagIsActive(this.FLAG_WEIGHT_CLASSES))this._removeFlag(this.FLAG_WEIGHT_CLASSES),this._attempts.push({articleContent:P,textLength:V});else if(this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY))this._removeFlag(this.FLAG_CLEAN_CONDITIONALLY),this._attempts.push({articleContent:P,textLength:V});else{if(this._attempts.push({articleContent:P,textLength:V}),this._attempts.sort((function(e,t){return t.textLength-e.textLength})),!this._attempts[0].textLength)return null;P=this._attempts[0].articleContent,G=!0}if(G){var W=[_,E].concat(this._getNodeAncestors(_));return this._someNode(W,(function(e){if(!e.tagName)return!1;var t=e.getAttribute("dir");return!!t&&(this._articleDir=t,!0)})),P}}},_isValidByline:function(e){return("string"==typeof e||e instanceof String)&&(e=e.trim()).length>0&&e.length<100},_unescapeHtmlEntities:function(e){if(!e)return e;var t=this.HTML_ESCAPE_MAP;return e.replace(/&(quot|amp|apos|lt|gt);/g,(function(e,n){return t[n]})).replace(/&#(?:x([0-9a-z]{1,4})|([0-9]{1,4}));/gi,(function(e,t,n){var i=parseInt(t||n,t?16:10);return String.fromCharCode(i)}))},_getJSONLD:function(e){var t,n=this._getAllNodesWithTag(e,["script"]);return this._forEachNode(n,(function(e){if(!t&&"application/ld+json"===e.getAttribute("type"))try{var n=e.textContent.replace(/^\s*<!\[CDATA\[|\]\]>\s*$/g,""),i=JSON.parse(n);if(!i["@context"]||!i["@context"].match(/^https?\:\/\/schema\.org$/))return;if(!i["@type"]&&Array.isArray(i["@graph"])&&(i=i["@graph"].find((function(e){return(e["@type"]||"").match(this.REGEXPS.jsonLdArticleTypes)}))),!i||!i["@type"]||!i["@type"].match(this.REGEXPS.jsonLdArticleTypes))return;if(t={},"string"==typeof i.name&&"string"==typeof i.headline&&i.name!==i.headline){var r=this._getArticleTitle(),o=this._textSimilarity(i.name,r)>.75,s=this._textSimilarity(i.headline,r)>.75;t.title=s&&!o?i.headline:i.name}else"string"==typeof i.name?t.title=i.name.trim():"string"==typeof i.headline&&(t.title=i.headline.trim());return i.author&&("string"==typeof i.author.name?t.byline=i.author.name.trim():Array.isArray(i.author)&&i.author[0]&&"string"==typeof i.author[0].name&&(t.byline=i.author.filter((function(e){return e&&"string"==typeof e.name})).map((function(e){return e.name.trim()})).join(", "))),"string"==typeof i.description&&(t.excerpt=i.description.trim()),void(i.publisher&&"string"==typeof i.publisher.name&&(t.siteName=i.publisher.name.trim()))}catch(e){this.log(e.message)}})),t||{}},_getArticleMetadata:function(e){var t={},n={},i=this._doc.getElementsByTagName("meta"),r=/\s*(dc|dcterm|og|twitter)\s*:\s*(author|creator|description|title|site_name)\s*/gi,o=/^\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\s*[\.:]\s*)?(author|creator|description|title|site_name)\s*$/i;return this._forEachNode(i,(function(e){var t=e.getAttribute("name"),i=e.getAttribute("property"),s=e.getAttribute("content");if(s){var a=null,l=null;i&&(a=i.match(r))&&(l=a[0].toLowerCase().replace(/\s/g,""),n[l]=s.trim()),!a&&t&&o.test(t)&&(l=t,s&&(l=l.toLowerCase().replace(/\s/g,"").replace(/\./g,":"),n[l]=s.trim()))}})),t.title=e.title||n["dc:title"]||n["dcterm:title"]||n["og:title"]||n["weibo:article:title"]||n["weibo:webpage:title"]||n.title||n["twitter:title"],t.title||(t.title=this._getArticleTitle()),t.byline=e.byline||n["dc:creator"]||n["dcterm:creator"]||n.author,t.excerpt=e.excerpt||n["dc:description"]||n["dcterm:description"]||n["og:description"]||n["weibo:article:description"]||n["weibo:webpage:description"]||n.description||n["twitter:description"],t.siteName=e.siteName||n["og:site_name"],t.title=this._unescapeHtmlEntities(t.title),t.byline=this._unescapeHtmlEntities(t.byline),t.excerpt=this._unescapeHtmlEntities(t.excerpt),t.siteName=this._unescapeHtmlEntities(t.siteName),t},_isSingleImage:function(e){return"IMG"===e.tagName||1===e.children.length&&""===e.textContent.trim()&&this._isSingleImage(e.children[0])},_unwrapNoscriptImages:function(e){var t=Array.from(e.getElementsByTagName("img"));this._forEachNode(t,(function(e){for(var t=0;t<e.attributes.length;t++){var n=e.attributes[t];switch(n.name){case"src":case"srcset":case"data-src":case"data-srcset":return}if(/\.(jpg|jpeg|png|webp)/i.test(n.value))return}e.parentNode.removeChild(e)}));var n=Array.from(e.getElementsByTagName("noscript"));this._forEachNode(n,(function(t){var n=e.createElement("div");if(n.innerHTML=t.innerHTML,this._isSingleImage(n)){var i=t.previousElementSibling;if(i&&this._isSingleImage(i)){var r=i;"IMG"!==r.tagName&&(r=i.getElementsByTagName("img")[0]);for(var o=n.getElementsByTagName("img")[0],s=0;s<r.attributes.length;s++){var a=r.attributes[s];if(""!==a.value&&("src"===a.name||"srcset"===a.name||/\.(jpg|jpeg|png|webp)/i.test(a.value))){if(o.getAttribute(a.name)===a.value)continue;var l=a.name;o.hasAttribute(l)&&(l="data-old-"+l),o.setAttribute(l,a.value)}}t.parentNode.replaceChild(n.firstElementChild,i)}}}))},_removeScripts:function(e){this._removeNodes(this._getAllNodesWithTag(e,["script"]),(function(e){return e.nodeValue="",e.removeAttribute("src"),!0})),this._removeNodes(this._getAllNodesWithTag(e,["noscript"]))},_hasSingleTagInsideElement:function(e,t){return 1==e.children.length&&e.children[0].tagName===t&&!this._someNode(e.childNodes,(function(e){return e.nodeType===this.TEXT_NODE&&this.REGEXPS.hasContent.test(e.textContent)}))},_isElementWithoutContent:function(e){return e.nodeType===this.ELEMENT_NODE&&0==e.textContent.trim().length&&(0==e.children.length||e.children.length==e.getElementsByTagName("br").length+e.getElementsByTagName("hr").length)},_hasChildBlockElement:function(e){return this._someNode(e.childNodes,(function(e){return this.DIV_TO_P_ELEMS.has(e.tagName)||this._hasChildBlockElement(e)}))},_isPhrasingContent:function(e){return e.nodeType===this.TEXT_NODE||-1!==this.PHRASING_ELEMS.indexOf(e.tagName)||("A"===e.tagName||"DEL"===e.tagName||"INS"===e.tagName)&&this._everyNode(e.childNodes,this._isPhrasingContent)},_isWhitespace:function(e){return e.nodeType===this.TEXT_NODE&&0===e.textContent.trim().length||e.nodeType===this.ELEMENT_NODE&&"BR"===e.tagName},_getInnerText:function(e,t){t=void 0===t||t;var n=e.textContent.trim();return t?n.replace(this.REGEXPS.normalize," "):n},_getCharCount:function(e,t){return t=t||",",this._getInnerText(e).split(t).length-1},_cleanStyles:function(e){if(e&&"svg"!==e.tagName.toLowerCase()){for(var t=0;t<this.PRESENTATIONAL_ATTRIBUTES.length;t++)e.removeAttribute(this.PRESENTATIONAL_ATTRIBUTES[t]);-1!==this.DEPRECATED_SIZE_ATTRIBUTE_ELEMS.indexOf(e.tagName)&&(e.removeAttribute("width"),e.removeAttribute("height"));for(var n=e.firstElementChild;null!==n;)this._cleanStyles(n),n=n.nextElementSibling}},_getLinkDensity:function(e){var t=this._getInnerText(e).length;if(0===t)return 0;var n=0;return this._forEachNode(e.getElementsByTagName("a"),(function(e){var t=e.getAttribute("href"),i=t&&this.REGEXPS.hashUrl.test(t)?.3:1;n+=this._getInnerText(e).length*i})),n/t},_getClassWeight:function(e){if(!this._flagIsActive(this.FLAG_WEIGHT_CLASSES))return 0;var t=0;return"string"==typeof e.className&&""!==e.className&&(this.REGEXPS.negative.test(e.className)&&(t-=25),this.REGEXPS.positive.test(e.className)&&(t+=25)),"string"==typeof e.id&&""!==e.id&&(this.REGEXPS.negative.test(e.id)&&(t-=25),this.REGEXPS.positive.test(e.id)&&(t+=25)),t},_clean:function(e,t){var n=-1!==["object","embed","iframe"].indexOf(t);this._removeNodes(this._getAllNodesWithTag(e,[t]),(function(e){if(n){for(var t=0;t<e.attributes.length;t++)if(this.REGEXPS.videos.test(e.attributes[t].value))return!1;if("object"===e.tagName&&this.REGEXPS.videos.test(e.innerHTML))return!1}return!0}))},_hasAncestorTag:function(e,t,n,i){n=n||3,t=t.toUpperCase();for(var r=0;e.parentNode;){if(n>0&&r>n)return!1;if(e.parentNode.tagName===t&&(!i||i(e.parentNode)))return!0;e=e.parentNode,r++}return!1},_getRowAndColumnCount:function(e){for(var t=0,n=0,i=e.getElementsByTagName("tr"),r=0;r<i.length;r++){var o=i[r].getAttribute("rowspan")||0;o&&(o=parseInt(o,10)),t+=o||1;for(var s=0,a=i[r].getElementsByTagName("td"),l=0;l<a.length;l++){var c=a[l].getAttribute("colspan")||0;c&&(c=parseInt(c,10)),s+=c||1}n=Math.max(n,s)}return{rows:t,columns:n}},_markDataTables:function(e){for(var t=e.getElementsByTagName("table"),n=0;n<t.length;n++){var i=t[n];if("presentation"!=i.getAttribute("role"))if("0"!=i.getAttribute("datatable"))if(i.getAttribute("summary"))i._readabilityDataTable=!0;else{var r=i.getElementsByTagName("caption")[0];if(r&&r.childNodes.length>0)i._readabilityDataTable=!0;else if(["col","colgroup","tfoot","thead","th"].some((function(e){return!!i.getElementsByTagName(e)[0]})))this.log("Data table because found data-y descendant"),i._readabilityDataTable=!0;else if(i.getElementsByTagName("table")[0])i._readabilityDataTable=!1;else{var o=this._getRowAndColumnCount(i);o.rows>=10||o.columns>4?i._readabilityDataTable=!0:i._readabilityDataTable=o.rows*o.columns>10}}else i._readabilityDataTable=!1;else i._readabilityDataTable=!1}},_fixLazyImages:function(e){this._forEachNode(this._getAllNodesWithTag(e,["img","picture","figure"]),(function(e){if(e.src&&this.REGEXPS.b64DataUrl.test(e.src)){if("image/svg+xml"===this.REGEXPS.b64DataUrl.exec(e.src)[1])return;for(var t=!1,n=0;n<e.attributes.length;n++){var i=e.attributes[n];if("src"!==i.name&&/\.(jpg|jpeg|png|webp)/i.test(i.value)){t=!0;break}}if(t){var r=e.src.search(/base64\s*/i)+7;e.src.length-r<133&&e.removeAttribute("src")}}if(!(e.src||e.srcset&&"null"!=e.srcset)||-1!==e.className.toLowerCase().indexOf("lazy"))for(var o=0;o<e.attributes.length;o++)if("src"!==(i=e.attributes[o]).name&&"srcset"!==i.name&&"alt"!==i.name){var s=null;if(/\.(jpg|jpeg|png|webp)\s+\d/.test(i.value)?s="srcset":/^\s*\S+\.(jpg|jpeg|png|webp)\S*\s*$/.test(i.value)&&(s="src"),s)if("IMG"===e.tagName||"PICTURE"===e.tagName)e.setAttribute(s,i.value);else if("FIGURE"===e.tagName&&!this._getAllNodesWithTag(e,["img","picture"]).length){var a=this._doc.createElement("img");a.setAttribute(s,i.value),e.appendChild(a)}}}))},_getTextDensity:function(e,t){var n=this._getInnerText(e,!0).length;if(0===n)return 0;var i=0,r=this._getAllNodesWithTag(e,t);return this._forEachNode(r,(e=>i+=this._getInnerText(e,!0).length)),i/n},_cleanConditionally:function(e,t){this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY)&&this._removeNodes(this._getAllNodesWithTag(e,[t]),(function(e){var n=function(e){return e._readabilityDataTable},i="ul"===t||"ol"===t;if(!i){var r=0,o=this._getAllNodesWithTag(e,["ul","ol"]);this._forEachNode(o,(e=>r+=this._getInnerText(e).length)),i=r/this._getInnerText(e).length>.9}if("table"===t&&n(e))return!1;if(this._hasAncestorTag(e,"table",-1,n))return!1;if(this._hasAncestorTag(e,"code"))return!1;var s=this._getClassWeight(e);if(this.log("Cleaning Conditionally",e),s+0<0)return!0;if(this._getCharCount(e,",")<10){for(var a=e.getElementsByTagName("p").length,l=e.getElementsByTagName("img").length,c=e.getElementsByTagName("li").length-100,u=e.getElementsByTagName("input").length,d=this._getTextDensity(e,["h1","h2","h3","h4","h5","h6"]),h=0,f=this._getAllNodesWithTag(e,["object","embed","iframe"]),g=0;g<f.length;g++){for(var m=0;m<f[g].attributes.length;m++)if(this.REGEXPS.videos.test(f[g].attributes[m].value))return!1;if("object"===f[g].tagName&&this.REGEXPS.videos.test(f[g].innerHTML))return!1;h++}var p=this._getLinkDensity(e),y=this._getInnerText(e).length;return l>1&&a/l<.5&&!this._hasAncestorTag(e,"figure")||!i&&c>a||u>Math.floor(a/3)||!i&&d<.9&&y<25&&(0===l||l>2)&&!this._hasAncestorTag(e,"figure")||!i&&s<25&&p>.2||s>=25&&p>.5||1===h&&y<75||h>1}return!1}))},_cleanMatchedNodes:function(e,t){for(var n=this._getNextNode(e,!0),i=this._getNextNode(e);i&&i!=n;)i=t.call(this,i,i.className+" "+i.id)?this._removeAndGetNext(i):this._getNextNode(i)},_cleanHeaders:function(e){let t=this._getAllNodesWithTag(e,["h1","h2"]);this._removeNodes(t,(function(e){let t=this._getClassWeight(e)<0;return t&&this.log("Removing header with low class weight:",e),t}))},_headerDuplicatesTitle:function(e){if("H1"!=e.tagName&&"H2"!=e.tagName)return!1;var t=this._getInnerText(e,!1);return this.log("Evaluating similarity of header:",t,this._articleTitle),this._textSimilarity(this._articleTitle,t)>.75},_flagIsActive:function(e){return(this._flags&e)>0},_removeFlag:function(e){this._flags=this._flags&~e},_isProbablyVisible:function(e){return(!e.style||"none"!=e.style.display)&&!e.hasAttribute("hidden")&&(!e.hasAttribute("aria-hidden")||"true"!=e.getAttribute("aria-hidden")||e.className&&e.className.indexOf&&-1!==e.className.indexOf("fallback-image"))},parse:function(){if(this._maxElemsToParse>0){var e=this._doc.getElementsByTagName("*").length;if(e>this._maxElemsToParse)throw new Error("Aborting parsing document; "+e+" elements found")}this._unwrapNoscriptImages(this._doc);var t=this._disableJSONLD?{}:this._getJSONLD(this._doc);this._removeScripts(this._doc),this._prepDocument();var n=this._getArticleMetadata(t);this._articleTitle=n.title;var i=this._grabArticle();if(!i)return null;if(this.log("Grabbed: "+i.innerHTML),this._postProcessContent(i),!n.excerpt){var r=i.getElementsByTagName("p");r.length>0&&(n.excerpt=r[0].textContent.trim())}var o=i.textContent;return{title:this._articleTitle,byline:n.byline||this._articleByline,dir:this._articleDir,lang:this._articleLang,content:this._serializer(i),textContent:o,length:o.length,excerpt:n.excerpt,siteName:n.siteName||this._articleSiteName}}},e.exports=t},107:(e,t,n)=>{var i=n(174),r=n(893);e.exports={Readability:i,isProbablyReaderable:r}},763:(e,t,n)=>{"use strict";var i;n.r(t),n.d(t,{AttributeAction:()=>o,IgnoreCaseMode:()=>r,SelectorType:()=>i,isTraversal:()=>u,parse:()=>p,stringify:()=>A}),function(e){e.Attribute="attribute",e.Pseudo="pseudo",e.PseudoElement="pseudo-element",e.Tag="tag",e.Universal="universal",e.Adjacent="adjacent",e.Child="child",e.Descendant="descendant",e.Parent="parent",e.Sibling="sibling",e.ColumnCombinator="column-combinator"}(i||(i={}));const r={Unknown:null,QuirksMode:"quirks",IgnoreCase:!0,CaseSensitive:!1};var o;!function(e){e.Any="any",e.Element="element",e.End="end",e.Equals="equals",e.Exists="exists",e.Hyphen="hyphen",e.Not="not",e.Start="start"}(o||(o={}));const s=/^[^\\#]?(?:\\(?:[\da-f]{1,6}\s?|.)|[\w\-\u00b0-\uFFFF])+/,a=/\\([\da-f]{1,6}\s?|(\s)|.)/gi,l=new Map([[126,o.Element],[94,o.Start],[36,o.End],[42,o.Any],[33,o.Not],[124,o.Hyphen]]),c=new Set(["has","not","matches","is","where","host","host-context"]);function u(e){switch(e.type){case i.Adjacent:case i.Child:case i.Descendant:case i.Parent:case i.Sibling:case i.ColumnCombinator:return!0;default:return!1}}const d=new Set(["contains","icontains"]);function h(e,t,n){const i=parseInt(t,16)-65536;return i!=i||n?t:i<0?String.fromCharCode(i+65536):String.fromCharCode(i>>10|55296,1023&i|56320)}function f(e){return e.replace(a,h)}function g(e){return 39===e||34===e}function m(e){return 32===e||9===e||10===e||12===e||13===e}function p(e){const t=[],n=y(t,`${e}`,0);if(n<e.length)throw new Error(`Unmatched selector: ${e.slice(n)}`);return t}function y(e,t,n){let r=[];function a(e){const i=t.slice(n+e).match(s);if(!i)throw new Error(`Expected name, found ${t.slice(n)}`);const[r]=i;return n+=e+r.length,f(r)}function h(e){for(n+=e;n<t.length&&m(t.charCodeAt(n));)n++}function p(){const e=n+=1;let i=1;for(;i>0&&n<t.length;n++)40!==t.charCodeAt(n)||v(n)?41!==t.charCodeAt(n)||v(n)||i--:i++;if(i)throw new Error("Parenthesis not matched");return f(t.slice(e,n-1))}function v(e){let n=0;for(;92===t.charCodeAt(--e);)n++;return 1==(1&n)}function b(){if(r.length>0&&u(r[r.length-1]))throw new Error("Did not expect successive traversals.")}function _(e){r.length>0&&r[r.length-1].type===i.Descendant?r[r.length-1].type=e:(b(),r.push({type:e}))}function E(e,t){r.push({type:i.Attribute,name:e,action:t,value:a(1),namespace:null,ignoreCase:"quirks"})}function N(){if(r.length&&r[r.length-1].type===i.Descendant&&r.pop(),0===r.length)throw new Error("Empty sub-selector");e.push(r)}if(h(0),t.length===n)return n;e:for(;n<t.length;){const e=t.charCodeAt(n);switch(e){case 32:case 9:case 10:case 12:case 13:0!==r.length&&r[0].type===i.Descendant||(b(),r.push({type:i.Descendant})),h(1);break;case 62:_(i.Child),h(1);break;case 60:_(i.Parent),h(1);break;case 126:_(i.Sibling),h(1);break;case 43:_(i.Adjacent),h(1);break;case 46:E("class",o.Element);break;case 35:E("id",o.Equals);break;case 91:{let e;h(1);let s=null;124===t.charCodeAt(n)?e=a(1):t.startsWith("*|",n)?(s="*",e=a(2)):(e=a(0),124===t.charCodeAt(n)&&61!==t.charCodeAt(n+1)&&(s=e,e=a(1))),h(0);let c=o.Exists;const u=l.get(t.charCodeAt(n));if(u){if(c=u,61!==t.charCodeAt(n+1))throw new Error("Expected `=`");h(2)}else 61===t.charCodeAt(n)&&(c=o.Equals,h(1));let d="",p=null;if("exists"!==c){if(g(t.charCodeAt(n))){const e=t.charCodeAt(n);let i=n+1;for(;i<t.length&&(t.charCodeAt(i)!==e||v(i));)i+=1;if(t.charCodeAt(i)!==e)throw new Error("Attribute value didn't end");d=f(t.slice(n+1,i)),n=i+1}else{const e=n;for(;n<t.length&&(!m(t.charCodeAt(n))&&93!==t.charCodeAt(n)||v(n));)n+=1;d=f(t.slice(e,n))}h(0);const e=32|t.charCodeAt(n);115===e?(p=!1,h(1)):105===e&&(p=!0,h(1))}if(93!==t.charCodeAt(n))throw new Error("Attribute selector didn't terminate");n+=1;const y={type:i.Attribute,name:e,action:c,value:d,namespace:s,ignoreCase:p};r.push(y);break}case 58:{if(58===t.charCodeAt(n+1)){r.push({type:i.PseudoElement,name:a(2).toLowerCase(),data:40===t.charCodeAt(n)?p():null});continue}const e=a(1).toLowerCase();let o=null;if(40===t.charCodeAt(n))if(c.has(e)){if(g(t.charCodeAt(n+1)))throw new Error(`Pseudo-selector ${e} cannot be quoted`);if(o=[],n=y(o,t,n+1),41!==t.charCodeAt(n))throw new Error(`Missing closing parenthesis in :${e} (${t})`);n+=1}else{if(o=p(),d.has(e)){const e=o.charCodeAt(0);e===o.charCodeAt(o.length-1)&&g(e)&&(o=o.slice(1,-1))}o=f(o)}r.push({type:i.Pseudo,name:e,data:o});break}case 44:N(),r=[],h(1);break;default:{if(t.startsWith("/*",n)){const e=t.indexOf("*/",n+2);if(e<0)throw new Error("Comment was not terminated");n=e+2,0===r.length&&h(0);break}let o,l=null;if(42===e)n+=1,o="*";else if(124===e){if(o="",124===t.charCodeAt(n+1)){_(i.ColumnCombinator),h(2);break}}else{if(!s.test(t.slice(n)))break e;o=a(0)}124===t.charCodeAt(n)&&124!==t.charCodeAt(n+1)&&(l=o,42===t.charCodeAt(n+1)?(o="*",n+=2):o=a(1)),r.push("*"===o?{type:i.Universal,namespace:l}:{type:i.Tag,name:o,namespace:l})}}}return N(),n}const v=["\\",'"',"%","'"],b=[...v,"(",")"],_=new Set(v.map((e=>e.charCodeAt(0)))),E=new Set(b.map((e=>e.charCodeAt(0)))),N=new Set([...b,"~","^","$","*","+","!","|",":","[","]"," ","."].map((e=>e.charCodeAt(0))));function A(e){return e.map((e=>e.map(T).join(""))).join(", ")}function T(e,t,n){switch(e.type){case i.Child:return 0===t?"> ":" > ";case i.Parent:return 0===t?"< ":" < ";case i.Sibling:return 0===t?"~ ":" ~ ";case i.Adjacent:return 0===t?"+ ":" + ";case i.Descendant:return" ";case i.ColumnCombinator:return 0===t?"|| ":" || ";case i.Universal:return"*"===e.namespace&&t+1<n.length&&"name"in n[t+1]?"":`${S(e.namespace)}*`;case i.Tag:return C(e);case i.PseudoElement:return`::${w(e.name,N)}${null===e.data?"":`(${w(e.data,E)})`}`;case i.Pseudo:return`:${w(e.name,N)}${null===e.data?"":`(${"string"==typeof e.data?w(e.data,E):A(e.data)})`}`;case i.Attribute:{if("id"===e.name&&e.action===o.Equals&&"quirks"===e.ignoreCase&&!e.namespace)return`#${w(e.value,N)}`;if("class"===e.name&&e.action===o.Element&&"quirks"===e.ignoreCase&&!e.namespace)return`.${w(e.value,N)}`;const t=C(e);return e.action===o.Exists?`[${t}]`:`[${t}${function(e){switch(e){case o.Equals:return"";case o.Element:return"~";case o.Start:return"^";case o.End:return"$";case o.Any:return"*";case o.Not:return"!";case o.Hyphen:return"|";case o.Exists:throw new Error("Shouldn't be here")}}(e.action)}="${w(e.value,_)}"${null===e.ignoreCase?"":e.ignoreCase?" i":" s"}]`}}}function C(e){return`${S(e.namespace)}${w(e.name,N)}`}function S(e){return null!==e?`${"*"===e?"*":w(e,N)}|`:""}function w(e,t){let n=0,i="";for(let r=0;r<e.length;r++)t.has(e.charCodeAt(r))&&(i+=`${e.slice(n,r)}\\${e.charAt(r)}`,n=r+1);return i.length>0?i+e.slice(n):e}},482:(e,t,n)=>{"use strict";n.r(t),n.d(t,{app:()=>E,h:()=>_,memo:()=>v,text:()=>b});var i={},r=[],o=e=>e,s=r.map,a=Array.isArray,l="undefined"!=typeof requestAnimationFrame?requestAnimationFrame:setTimeout,c=e=>{var t="";if("string"==typeof e)return e;if(a(e))for(var n,i=0;i<e.length;i++)(n=c(e[i]))&&(t+=(t&&" ")+n);else for(var i in e)e[i]&&(t+=(t&&" ")+i);return t},u=(e,t)=>{for(var n in{...e,...t})if("function"==typeof(a(e[n])?e[n][0]:e[n]))t[n]=e[n];else if(e[n]!==t[n])return!0},d=e=>null==e?e:e.key,h=(e,t,n,i,r,o)=>{if("style"===t)for(var s in{...n,...i})n=null==i||null==i[s]?"":i[s],"-"===s[0]?e[t].setProperty(s,n):e[t][s]=n;else"o"===t[0]&&"n"===t[1]?((e.events||(e.events={}))[t=t.slice(2)]=i)?n||e.addEventListener(t,r):e.removeEventListener(t,r):!o&&"list"!==t&&"form"!==t&&t in e?e[t]=null==i?"":i:null==i||!1===i?e.removeAttribute(t):e.setAttribute(t,i)},f=(e,t,n)=>{var i=e.props,r=3===e.type?document.createTextNode(e.tag):(n=n||"svg"===e.tag)?document.createElementNS("http://www.w3.org/2000/svg",e.tag,i.is&&i):document.createElement(e.tag,i.is&&i);for(var o in i)h(r,o,null,i[o],t,n);for(var s=0;s<e.children.length;s++)r.appendChild(f(e.children[s]=m(e.children[s]),t,n));return e.node=r},g=(e,t,n,i,r,o)=>{if(n===i);else if(null!=n&&3===n.type&&3===i.type)n.tag!==i.tag&&(t.nodeValue=i.tag);else if(null==n||n.tag!==i.tag)t=e.insertBefore(f(i=m(i),r,o),t),null!=n&&e.removeChild(n.node);else{var s,a,l,c,u=n.props,p=i.props,y=n.children,v=i.children,b=0,_=0,E=y.length-1,N=v.length-1;for(var A in o=o||"svg"===i.tag,{...u,...p})("value"===A||"selected"===A||"checked"===A?t[A]:u[A])!==p[A]&&h(t,A,u[A],p[A],r,o);for(;_<=N&&b<=E&&null!=(l=d(y[b]))&&l===d(v[_]);)g(t,y[b].node,y[b],v[_]=m(v[_++],y[b++]),r,o);for(;_<=N&&b<=E&&null!=(l=d(y[E]))&&l===d(v[N]);)g(t,y[E].node,y[E],v[N]=m(v[N--],y[E--]),r,o);if(b>E)for(;_<=N;)t.insertBefore(f(v[_]=m(v[_++]),r,o),(a=y[b])&&a.node);else if(_>N)for(;b<=E;)t.removeChild(y[b++].node);else{var T={},C={};for(A=b;A<=E;A++)null!=(l=y[A].key)&&(T[l]=y[A]);for(;_<=N;)l=d(a=y[b]),c=d(v[_]=m(v[_],a)),C[l]||null!=c&&c===d(y[b+1])?(null==l&&t.removeChild(a.node),b++):null==c||1===n.type?(null==l&&(g(t,a&&a.node,a,v[_],r,o),_++),b++):(l===c?(g(t,a.node,a,v[_],r,o),C[c]=!0,b++):null!=(s=T[c])?(g(t,t.insertBefore(s.node,a&&a.node),s,v[_],r,o),C[c]=!0):g(t,a&&a.node,null,v[_],r,o),_++);for(;b<=E;)null==d(a=y[b++])&&t.removeChild(a.node);for(var A in T)null==C[A]&&t.removeChild(T[A].node)}}return i.node=t},m=(e,t)=>!0!==e&&!1!==e&&e?"function"==typeof e.tag?((!t||null==t.memo||((e,t)=>{for(var n in e)if(e[n]!==t[n])return!0;for(var n in t)if(e[n]!==t[n])return!0})(t.memo,e.memo))&&((t=e.tag(e.memo)).memo=e.memo),t):e:b(""),p=e=>3===e.nodeType?b(e.nodeValue,e):y(e.nodeName.toLowerCase(),i,s.call(e.childNodes,p),1,e),y=(e,{key:t,...n},i,r,o)=>({tag:e,props:n,key:t,children:i,type:r,node:o}),v=(e,t)=>({tag:e,memo:t}),b=(e,t)=>y(e,i,r,3,t),_=(e,{class:t,...n},o=r)=>y(e,{...n,...t?{class:c(t)}:i},a(o)?o:[o]),E=({node:e,view:t,subscriptions:n,dispatch:s=o,init:c=i})=>{var d,h,f=e&&p(e),m=[],y=e=>{d!==e&&(null==(d=e)&&(s=n=v=o),n&&(m=((e,t=r,n)=>{for(var i,o,s=[],a=0;a<e.length||a<t.length;a++)i=e[a],o=t[a],s.push(o&&!0!==o?!i||o[0]!==i[0]||u(o[1],i[1])?[o[0],o[1],(i&&i[2](),o[0](n,o[1]))]:i:i&&i[2]());return s})(m,n(d),s)),t&&!h&&l(v,h=!0))},v=()=>e=g(e.parentNode,e,f,f=t(d),b,h=!1),b=function(e){s(this.events[e.type],e)};return(s=s(((e,t)=>"function"==typeof e?s(e(d,t)):a(e)?"function"==typeof e[0]?s(e[0],e[1]):e.slice(1).map((e=>e&&!0!==e&&(e[0]||e)(s,e[1])),y(e[0])):y(e))))(c),s}},302:(e,t,n)=>{"use strict";n.r(t),n.d(t,{calculate:()=>i,compare:()=>o});var i=function(e){var t,n,i,o,s=[];for(i=0,o=(t=e.split(",")).length;i<o;i+=1)(n=t[i]).length>0&&s.push(r(n));return s},r=function(e){var t,n,i=e,r={a:0,b:0,c:0},o=[];return t=function(t,n){var s,a,l,c,u,d;if(t.test(i))for(a=0,l=(s=i.match(t)).length;a<l;a+=1)r[n]+=1,c=s[a],u=i.indexOf(c),d=c.length,o.push({selector:e.substr(u,d),type:n,index:u,length:d}),i=i.replace(c,Array(d+1).join(" "))},(n=function(e){var t,n,r,o;if(e.test(i))for(n=0,r=(t=i.match(e)).length;n<r;n+=1)o=t[n],i=i.replace(o,Array(o.length+1).join("A"))})(/\\[0-9A-Fa-f]{6}\s?/g),n(/\\[0-9A-Fa-f]{1,5}\s/g),n(/\\./g),function(){var e,t,n,r,o=/{[^]*/gm;if(o.test(i))for(t=0,n=(e=i.match(o)).length;t<n;t+=1)r=e[t],i=i.replace(r,Array(r.length+1).join(" "))}(),t(/(\[[^\]]+\])/g,"b"),t(/(#[^\#\s\+>~\.\[:\)]+)/g,"a"),t(/(\.[^\s\+>~\.\[:\)]+)/g,"b"),t(/(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/gi,"c"),t(/(:(?!not|global|local)[\w-]+\([^\)]*\))/gi,"b"),t(/(:(?!not|global|local)[^\s\+>~\.\[:]+)/g,"b"),i=(i=(i=(i=(i=(i=i.replace(/[\*\s\+>~]/g," ")).replace(/[#\.]/g," ")).replace(/:not/g," ")).replace(/:local/g," ")).replace(/:global/g," ")).replace(/[\(\)]/g," "),t(/([^\s\+>~\.\[:]+)/g,"c"),o.sort((function(e,t){return e.index-t.index})),{selector:e,specificity:"0,"+r.a.toString()+","+r.b.toString()+","+r.c.toString(),specificityArray:[0,r.a,r.b,r.c],parts:o}},o=function(e,t){var n,i,o;if("string"==typeof e){if(-1!==e.indexOf(","))throw"Invalid CSS selector";n=r(e).specificityArray}else{if(!Array.isArray(e))throw"Invalid CSS selector or specificity array";if(4!==e.filter((function(e){return"number"==typeof e})).length)throw"Invalid specificity array";n=e}if("string"==typeof t){if(-1!==t.indexOf(","))throw"Invalid CSS selector";i=r(t).specificityArray}else{if(!Array.isArray(t))throw"Invalid CSS selector or specificity array";if(4!==t.filter((function(e){return"number"==typeof e})).length)throw"Invalid specificity array";i=t}for(o=0;o<4;o+=1){if(n[o]<i[o])return-1;if(n[o]>i[o])return 1}return 0}}},t={};function n(i){var r=t[i];if(void 0!==r)return r.exports;var o=t[i]={exports:{}};return e[i].call(o.exports,o,o.exports,n),o.exports}n.d=(e,t)=>{for(var i in t)n.o(t,i)&&!n.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{"use strict";const e=n(590);n.g.Clipper={clipArticle:e.clipArticle,clipPage:e.clipPage}})()})(); \ No newline at end of file diff --git a/apps/theme-builder/package-lock.json b/apps/theme-builder/package-lock.json index 6edcddad4..2365d96fb 100644 --- a/apps/theme-builder/package-lock.json +++ b/apps/theme-builder/package-lock.json @@ -1404,6 +1404,7 @@ "@react-pdf-viewer/core": "^3.12.0", "@react-pdf-viewer/toolbar": "^3.12.0", "@tanstack/react-query": "^4.29.19", + "@tanstack/react-virtual": "^3.0.0-beta.68", "@theme-ui/color": "^0.14.7", "@theme-ui/components": "^0.14.7", "@theme-ui/core": "^0.14.7", @@ -1438,7 +1439,6 @@ "react-modal": "3.13.1", "react-qrcode-logo": "^2.2.1", "react-scroll-sync": "^0.9.0", - "react-virtuoso": "^4.4.2", "timeago.js": "4.0.2", "tinycolor2": "^1.6.0", "w3c-keyname": "^2.2.6",