mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
web: convert more code to typescript
This commit is contained in:
@@ -23,7 +23,16 @@ import useSlider from "./hooks/use-slider";
|
|||||||
import useMobile from "./hooks/use-mobile";
|
import useMobile from "./hooks/use-mobile";
|
||||||
import useTablet from "./hooks/use-tablet";
|
import useTablet from "./hooks/use-tablet";
|
||||||
|
|
||||||
export default function MobileAppEffects({ sliderId, overlayId, setShow }) {
|
type MobileAppEffectsProps = {
|
||||||
|
sliderId: string;
|
||||||
|
overlayId: string;
|
||||||
|
setShow: (show: boolean) => void;
|
||||||
|
};
|
||||||
|
export default function MobileAppEffects({
|
||||||
|
sliderId,
|
||||||
|
overlayId,
|
||||||
|
setShow
|
||||||
|
}: MobileAppEffectsProps) {
|
||||||
const isMobile = useMobile();
|
const isMobile = useMobile();
|
||||||
const isTablet = useTablet();
|
const isTablet = useTablet();
|
||||||
const toggleSideMenu = useStore((store) => store.toggleSideMenu);
|
const toggleSideMenu = useStore((store) => store.toggleSideMenu);
|
||||||
@@ -40,6 +49,7 @@ export default function MobileAppEffects({ sliderId, overlayId, setShow }) {
|
|||||||
|
|
||||||
const percent = offset - (position / width) * offset;
|
const percent = offset - (position / width) * offset;
|
||||||
const overlay = document.getElementById("overlay");
|
const overlay = document.getElementById("overlay");
|
||||||
|
if (!overlay) return;
|
||||||
if (percent > 0) {
|
if (percent > 0) {
|
||||||
overlay.style.opacity = `${percent}%`;
|
overlay.style.opacity = `${percent}%`;
|
||||||
overlay.style.pointerEvents = "all";
|
overlay.style.pointerEvents = "all";
|
||||||
@@ -74,6 +84,7 @@ export default function MobileAppEffects({ sliderId, overlayId, setShow }) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!overlayId) return;
|
if (!overlayId) return;
|
||||||
const overlay = document.getElementById(overlayId);
|
const overlay = document.getElementById(overlayId);
|
||||||
|
if (!overlay) return;
|
||||||
overlay.onclick = () => toggleSideMenu(false);
|
overlay.onclick = () => toggleSideMenu(false);
|
||||||
return () => {
|
return () => {
|
||||||
overlay.onclick = null;
|
overlay.onclick = null;
|
||||||
@@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useStore } from "./stores/app-store";
|
import { useStore } from "./stores/app-store";
|
||||||
import { useStore as useUserStore } from "./stores/user-store";
|
import { useStore as useUserStore } from "./stores/user-store";
|
||||||
import { useStore as useNotesStore } from "./stores/note-store";
|
|
||||||
import { useStore as useThemeStore } from "./stores/theme-store";
|
import { useStore as useThemeStore } from "./stores/theme-store";
|
||||||
import { useStore as useAttachmentStore } from "./stores/attachment-store";
|
import { useStore as useAttachmentStore } from "./stores/attachment-store";
|
||||||
import { useStore as useEditorStore } from "./stores/editor-store";
|
import { useStore as useEditorStore } from "./stores/editor-store";
|
||||||
@@ -47,11 +46,13 @@ import { interruptedOnboarding } from "./dialogs/onboarding-dialog";
|
|||||||
import { hashNavigate } from "./navigation";
|
import { hashNavigate } from "./navigation";
|
||||||
import { desktop } from "./common/desktop-bridge";
|
import { desktop } from "./common/desktop-bridge";
|
||||||
|
|
||||||
export default function AppEffects({ setShow }) {
|
type AppEffectsProps = {
|
||||||
|
setShow: (show: boolean) => void;
|
||||||
|
};
|
||||||
|
export default function AppEffects({ setShow }: AppEffectsProps) {
|
||||||
const refreshNavItems = useStore((store) => store.refreshNavItems);
|
const refreshNavItems = useStore((store) => store.refreshNavItems);
|
||||||
const updateLastSynced = useStore((store) => store.updateLastSynced);
|
const updateLastSynced = useStore((store) => store.updateLastSynced);
|
||||||
const isFocusMode = useStore((store) => store.isFocusMode);
|
const isFocusMode = useStore((store) => store.isFocusMode);
|
||||||
const addReminder = useStore((store) => store.addReminder);
|
|
||||||
const initUser = useUserStore((store) => store.init);
|
const initUser = useUserStore((store) => store.init);
|
||||||
const initStore = useStore((store) => store.init);
|
const initStore = useStore((store) => store.init);
|
||||||
const initAttachments = useAttachmentStore((store) => store.init);
|
const initAttachments = useAttachmentStore((store) => store.init);
|
||||||
@@ -68,7 +69,7 @@ export default function AppEffects({ setShow }) {
|
|||||||
function initializeApp() {
|
function initializeApp() {
|
||||||
const userCheckStatusEvent = EV.subscribe(
|
const userCheckStatusEvent = EV.subscribe(
|
||||||
EVENTS.userCheckStatus,
|
EVENTS.userCheckStatus,
|
||||||
async (type) => {
|
async (type: string) => {
|
||||||
if (isUserPremium()) {
|
if (isUserPremium()) {
|
||||||
return { type, result: true };
|
return { type, result: true };
|
||||||
} else {
|
} else {
|
||||||
@@ -93,7 +94,7 @@ export default function AppEffects({ setShow }) {
|
|||||||
showUpgradeReminderDialogs();
|
showUpgradeReminderDialogs();
|
||||||
}
|
}
|
||||||
await resetReminders();
|
await resetReminders();
|
||||||
setIsVaultCreated(await db.vault.exists());
|
setIsVaultCreated(await db.vault?.exists());
|
||||||
|
|
||||||
await showOnboardingDialog(interruptedOnboarding());
|
await showOnboardingDialog(interruptedOnboarding());
|
||||||
await showFeatureDialog("highlights");
|
await showFeatureDialog("highlights");
|
||||||
@@ -111,23 +112,29 @@ export default function AppEffects({ setShow }) {
|
|||||||
updateLastSynced,
|
updateLastSynced,
|
||||||
refreshNavItems,
|
refreshNavItems,
|
||||||
initUser,
|
initUser,
|
||||||
initNotes,
|
|
||||||
addReminder,
|
|
||||||
setIsVaultCreated
|
setIsVaultCreated
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const systemTimeInvalidEvent = EV.subscribe(
|
// const systemTimeInvalidEvent = EV.subscribe(
|
||||||
EVENTS.systemTimeInvalid,
|
// EVENTS.systemTimeInvalid,
|
||||||
async ({ serverTime, localTime }) => {
|
// async ({ serverTime, localTime }) => {
|
||||||
await showInvalidSystemTimeDialog({ serverTime, localTime });
|
// await showInvalidSystemTimeDialog({ serverTime, localTime });
|
||||||
}
|
// }
|
||||||
);
|
// );
|
||||||
|
|
||||||
const attachmentsLoadingEvent = EV.subscribe(
|
const attachmentsLoadingEvent = EV.subscribe(
|
||||||
EVENTS.attachmentsLoading,
|
EVENTS.attachmentsLoading,
|
||||||
({ type, total, current }) => {
|
({
|
||||||
|
type,
|
||||||
|
total,
|
||||||
|
current
|
||||||
|
}: {
|
||||||
|
type: ProcessingType;
|
||||||
|
total: number;
|
||||||
|
current: number;
|
||||||
|
}) => {
|
||||||
const [key, status] = getProcessingStatusFromType(type);
|
const [key, status] = getProcessingStatusFromType(type);
|
||||||
|
|
||||||
if (current === total) {
|
if (current === total) {
|
||||||
@@ -144,7 +151,15 @@ export default function AppEffects({ setShow }) {
|
|||||||
|
|
||||||
const progressEvent = AppEventManager.subscribe(
|
const progressEvent = AppEventManager.subscribe(
|
||||||
AppEvents.UPDATE_ATTACHMENT_PROGRESS,
|
AppEvents.UPDATE_ATTACHMENT_PROGRESS,
|
||||||
({ type, total, loaded }) => {
|
({
|
||||||
|
type,
|
||||||
|
total,
|
||||||
|
loaded
|
||||||
|
}: {
|
||||||
|
type: ProcessingType;
|
||||||
|
total: number;
|
||||||
|
loaded: number;
|
||||||
|
}) => {
|
||||||
const [key, status] = getProcessingStatusFromType(type);
|
const [key, status] = getProcessingStatusFromType(type);
|
||||||
if (!key) return;
|
if (!key) return;
|
||||||
|
|
||||||
@@ -167,7 +182,7 @@ export default function AppEffects({ setShow }) {
|
|||||||
return () => {
|
return () => {
|
||||||
attachmentsLoadingEvent.unsubscribe();
|
attachmentsLoadingEvent.unsubscribe();
|
||||||
progressEvent.unsubscribe();
|
progressEvent.unsubscribe();
|
||||||
systemTimeInvalidEvent.unsubscribe();
|
// systemTimeInvalidEvent.unsubscribe();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -221,7 +236,8 @@ export default function AppEffects({ setShow }) {
|
|||||||
return <React.Fragment />;
|
return <React.Fragment />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProcessingStatusFromType(type) {
|
type ProcessingType = "download" | "upload" | "encrypt";
|
||||||
|
function getProcessingStatusFromType(type: ProcessingType) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "download":
|
case "download":
|
||||||
return ["downloadingAttachments", "Downloading"];
|
return ["downloadingAttachments", "Downloading"];
|
||||||
@@ -230,6 +246,6 @@ function getProcessingStatusFromType(type) {
|
|||||||
case "encrypt":
|
case "encrypt":
|
||||||
return ["encryptingAttachments", "Encrypting"];
|
return ["encryptingAttachments", "Encrypting"];
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ import useMobile from "./hooks/use-mobile";
|
|||||||
import useTablet from "./hooks/use-tablet";
|
import useTablet from "./hooks/use-tablet";
|
||||||
import { LazyMotion, domAnimation } from "framer-motion";
|
import { LazyMotion, domAnimation } from "framer-motion";
|
||||||
import useDatabase from "./hooks/use-database";
|
import useDatabase from "./hooks/use-database";
|
||||||
import { Allotment, LayoutPriority } from "allotment";
|
import { Allotment, AllotmentHandle, LayoutPriority } from "allotment";
|
||||||
import { useStore } from "./stores/app-store";
|
import { useStore } from "./stores/app-store";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
import { ViewLoader } from "./components/loaders/view-loader";
|
import { ViewLoader } from "./components/loaders/view-loader";
|
||||||
@@ -38,8 +38,8 @@ import { usePersistentState } from "./hooks/use-persistent-state";
|
|||||||
|
|
||||||
new WebExtensionRelay();
|
new WebExtensionRelay();
|
||||||
|
|
||||||
const GlobalMenuWrapper = React.lazy(() =>
|
const GlobalMenuWrapper = React.lazy(
|
||||||
import("./components/global-menu-wrapper")
|
() => import("./components/global-menu-wrapper")
|
||||||
);
|
);
|
||||||
const AppEffects = React.lazy(() => import("./app-effects"));
|
const AppEffects = React.lazy(() => import("./app-effects"));
|
||||||
const MobileAppEffects = React.lazy(() => import("./app-effects.mobile"));
|
const MobileAppEffects = React.lazy(() => import("./app-effects.mobile"));
|
||||||
@@ -91,9 +91,25 @@ function App() {
|
|||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
||||||
function SuspenseLoader({ condition, props, component: Component, fallback }) {
|
type SuspenseLoaderProps<TComponent extends React.JSXElementConstructor<any>> =
|
||||||
|
{
|
||||||
|
condition: boolean;
|
||||||
|
props?: React.ComponentProps<TComponent>;
|
||||||
|
component: TComponent;
|
||||||
|
fallback: JSX.Element;
|
||||||
|
};
|
||||||
|
|
||||||
|
function SuspenseLoader<TComponent extends React.JSXElementConstructor<any>>({
|
||||||
|
condition,
|
||||||
|
props,
|
||||||
|
component,
|
||||||
|
fallback
|
||||||
|
}: SuspenseLoaderProps<TComponent>) {
|
||||||
if (!condition) return fallback;
|
if (!condition) return fallback;
|
||||||
|
|
||||||
|
const Component = component as (
|
||||||
|
props: any
|
||||||
|
) => React.ReactComponentElement<any, any>;
|
||||||
return (
|
return (
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={
|
fallback={
|
||||||
@@ -105,14 +121,23 @@ function SuspenseLoader({ condition, props, component: Component, fallback }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DesktopAppContents({ isAppLoaded, show, setShow }) {
|
type DesktopAppContentsProps = {
|
||||||
|
isAppLoaded: boolean;
|
||||||
|
show: boolean;
|
||||||
|
setShow: (show: boolean) => void;
|
||||||
|
};
|
||||||
|
function DesktopAppContents({
|
||||||
|
isAppLoaded,
|
||||||
|
show,
|
||||||
|
setShow
|
||||||
|
}: DesktopAppContentsProps) {
|
||||||
const isFocusMode = useStore((store) => store.isFocusMode);
|
const isFocusMode = useStore((store) => store.isFocusMode);
|
||||||
const isTablet = useTablet();
|
const isTablet = useTablet();
|
||||||
const [paneSizes, setPaneSizes] = usePersistentState("paneSizes", [
|
const [paneSizes, setPaneSizes] = usePersistentState("paneSizes", [
|
||||||
isTablet ? 60 : 180,
|
isTablet ? 60 : 180,
|
||||||
isTablet ? 240 : 380
|
isTablet ? 240 : 380
|
||||||
]);
|
]);
|
||||||
const panesRef = useRef();
|
const panesRef = useRef<AllotmentHandle>(null);
|
||||||
const [isNarrow, setIsNarrow] = useState(paneSizes[0] <= 55);
|
const [isNarrow, setIsNarrow] = useState(paneSizes[0] <= 55);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -184,7 +209,7 @@ function DesktopAppContents({ isAppLoaded, show, setShow }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MobileAppContents({ isAppLoaded }) {
|
function MobileAppContents({ isAppLoaded }: { isAppLoaded: boolean }) {
|
||||||
return (
|
return (
|
||||||
<FlexScrollContainer
|
<FlexScrollContainer
|
||||||
id="slider"
|
id="slider"
|
||||||
@@ -648,7 +648,7 @@ export function showSettings() {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showOnboardingDialog(type: string) {
|
export function showOnboardingDialog(type?: string) {
|
||||||
if (!type) return;
|
if (!type) return;
|
||||||
return showDialog("OnboardingDialog", (Dialog, perform) => (
|
return showDialog("OnboardingDialog", (Dialog, perform) => (
|
||||||
<Dialog type={type} onClose={(res: boolean) => perform(res)} />
|
<Dialog type={type} onClose={(res: boolean) => perform(res)} />
|
||||||
|
|||||||
@@ -1,72 +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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const SINGLE_LINE_HEIGHT = 1.4;
|
|
||||||
const DEFAULT_FONT_SIZE = document.getElementById("p").clientHeight - 1;
|
|
||||||
|
|
||||||
const MAX_HEIGHTS = {
|
|
||||||
note: SINGLE_LINE_HEIGHT * 7 * DEFAULT_FONT_SIZE,
|
|
||||||
notebook: SINGLE_LINE_HEIGHT * 7 * DEFAULT_FONT_SIZE,
|
|
||||||
generic: SINGLE_LINE_HEIGHT * 4 * DEFAULT_FONT_SIZE
|
|
||||||
};
|
|
||||||
|
|
||||||
function getNoteHeight(item) {
|
|
||||||
const { notebooks, headline } = item;
|
|
||||||
let height = SINGLE_LINE_HEIGHT * 3;
|
|
||||||
//if (title.length > 35) height += SINGLE_LINE_HEIGHT;
|
|
||||||
if (headline?.length > 0) height += SINGLE_LINE_HEIGHT * 2;
|
|
||||||
else height += SINGLE_LINE_HEIGHT;
|
|
||||||
if (notebooks?.length) height += SINGLE_LINE_HEIGHT;
|
|
||||||
|
|
||||||
return height * DEFAULT_FONT_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNotebookHeight(item) {
|
|
||||||
const { topics, description, title } = item;
|
|
||||||
// at the minimum we will have a title and the info text
|
|
||||||
let height = SINGLE_LINE_HEIGHT * 3; // 2.8 = 2 lines
|
|
||||||
|
|
||||||
if (title.length > 35) {
|
|
||||||
height += SINGLE_LINE_HEIGHT; // title has become multiline
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topics.length > 0) {
|
|
||||||
height += SINGLE_LINE_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (description?.length > 0) {
|
|
||||||
height += SINGLE_LINE_HEIGHT * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return height * DEFAULT_FONT_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getItemHeight(item) {
|
|
||||||
const { title } = item;
|
|
||||||
// at the minimum we will have a title and the info text
|
|
||||||
let height = SINGLE_LINE_HEIGHT * 3; // 2.8 = 2 lines
|
|
||||||
|
|
||||||
if (title.length > 30) {
|
|
||||||
height += SINGLE_LINE_HEIGHT; // title has become multiline
|
|
||||||
}
|
|
||||||
|
|
||||||
return height * DEFAULT_FONT_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
export { getNoteHeight, getNotebookHeight, getItemHeight, MAX_HEIGHTS };
|
|
||||||
@@ -33,11 +33,6 @@ const SINGLE_LINE_HEIGHT = 1.4;
|
|||||||
const DEFAULT_LINE_HEIGHT =
|
const DEFAULT_LINE_HEIGHT =
|
||||||
(document.getElementById("p")?.clientHeight || 16) - 1;
|
(document.getElementById("p")?.clientHeight || 16) - 1;
|
||||||
export const DEFAULT_ITEM_HEIGHT = SINGLE_LINE_HEIGHT * 2 * DEFAULT_LINE_HEIGHT;
|
export const DEFAULT_ITEM_HEIGHT = SINGLE_LINE_HEIGHT * 2 * DEFAULT_LINE_HEIGHT;
|
||||||
// const MAX_HEIGHTS = {
|
|
||||||
// note: SINGLE_LINE_HEIGHT * 7 * DEFAULT_LINE_HEIGHT,
|
|
||||||
// notebook: SINGLE_LINE_HEIGHT * 7 * DEFAULT_LINE_HEIGHT,
|
|
||||||
// generic: SINGLE_LINE_HEIGHT * 4 * DEFAULT_LINE_HEIGHT
|
|
||||||
// };
|
|
||||||
|
|
||||||
export type Item = { id: string; type: string; title: string } & Record<
|
export type Item = { id: string; type: string; title: string } & Record<
|
||||||
string,
|
string,
|
||||||
|
|||||||
@@ -20,14 +20,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { NavigationEvents } from "../navigation";
|
import { NavigationEvents } from "../navigation";
|
||||||
|
|
||||||
function useNavigate(routeKey, onNavigation) {
|
function useNavigate(routeKey: string, onNavigation: () => void) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onNavigation();
|
onNavigation();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function onNavigate(route) {
|
function onNavigate(route: { key: string }) {
|
||||||
if (route?.key === routeKey) {
|
if (route?.key === routeKey) {
|
||||||
onNavigation();
|
onNavigation();
|
||||||
}
|
}
|
||||||
@@ -72,9 +72,6 @@ class AnnouncementStore extends BaseStore {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {[import("zustand").UseStore<AnnouncementStore>, AnnouncementStore]}
|
|
||||||
*/
|
|
||||||
const [useStore, store] = createStore(AnnouncementStore);
|
const [useStore, store] = createStore(AnnouncementStore);
|
||||||
export { useStore, store };
|
export { useStore, store };
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user