web: convert more code to typescript

This commit is contained in:
Abdullah Atta
2023-07-04 22:44:55 +05:00
parent 56f6d34995
commit fb32aedd69
11 changed files with 81 additions and 109 deletions

View File

@@ -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;

View File

@@ -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 [];
} }
} }

View File

@@ -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"

View File

@@ -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)} />

View File

@@ -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 };

View File

@@ -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,

View File

@@ -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();
} }

View File

@@ -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 };