diff --git a/apps/client/src/layouts/mobile_layout.tsx b/apps/client/src/layouts/mobile_layout.tsx
index e194bb7271..3fc5422b0a 100644
--- a/apps/client/src/layouts/mobile_layout.tsx
+++ b/apps/client/src/layouts/mobile_layout.tsx
@@ -23,8 +23,6 @@ import NoteTreeWidget from "../widgets/note_tree.js";
import NoteWrapperWidget from "../widgets/note_wrapper.js";
import NoteDetail from "../widgets/NoteDetail.jsx";
import QuickSearchWidget from "../widgets/quick_search.js";
-import { useNoteContext } from "../widgets/react/hooks.jsx";
-import FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx";
import ScrollPadding from "../widgets/scroll_padding";
import SearchResult from "../widgets/search_result.jsx";
import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx";
diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css
index 2a6d66ed6c..8950f3fd3f 100644
--- a/apps/client/src/stylesheets/style.css
+++ b/apps/client/src/stylesheets/style.css
@@ -1587,7 +1587,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
position: absolute;
top: 0;
inset-inline-start: 0;
- bottom: 0;
+ height: 100dvh;
width: 85vw;
padding-top: env(safe-area-inset-top);
transition: transform 250ms ease-in-out;
@@ -1651,13 +1651,27 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
word-break: break-all;
}
- body.mobile .jump-to-note-dialog .modal-content {
- overflow-y: auto;
- }
+ body.mobile .jump-to-note-dialog {
+ .modal-header {
+ padding-bottom: 0.75rem !important;
+ }
- body.mobile .jump-to-note-dialog .modal-dialog .aa-dropdown-menu {
- max-height: unset;
- overflow: auto;
+ .modal-content {
+ padding-bottom: 0 !important;
+ }
+
+ .modal-body {
+ overflow-y: auto;
+ }
+
+ .aa-dropdown-menu {
+ max-height: unset;
+ overflow: auto;
+ }
+
+ .aa-suggestion {
+ padding-inline: 0;
+ }
}
body.mobile .modal-dialog .dropdown-menu {
diff --git a/apps/client/src/widgets/buttons/global_menu.tsx b/apps/client/src/widgets/buttons/global_menu.tsx
index 9db0393692..25f48c5db2 100644
--- a/apps/client/src/widgets/buttons/global_menu.tsx
+++ b/apps/client/src/widgets/buttons/global_menu.tsx
@@ -47,6 +47,7 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
>
{isMobile() && <>
+
>}
diff --git a/apps/client/src/widgets/launch_bar/launch_bar_widgets.tsx b/apps/client/src/widgets/launch_bar/launch_bar_widgets.tsx
index 639b5aede7..288565cf7b 100644
--- a/apps/client/src/widgets/launch_bar/launch_bar_widgets.tsx
+++ b/apps/client/src/widgets/launch_bar/launch_bar_widgets.tsx
@@ -3,11 +3,14 @@ import { createContext } from "preact";
import { useContext } from "preact/hooks";
import FNote from "../../entities/fnote";
+import utils from "../../services/utils";
import ActionButton, { ActionButtonProps } from "../react/ActionButton";
import Dropdown, { DropdownProps } from "../react/Dropdown";
import { useNoteLabel, useNoteProperty } from "../react/hooks";
import Icon from "../react/Icon";
+const cachedIsMobile = utils.isMobile();
+
export const LaunchBarContext = createContext<{
isHorizontalLayout: boolean;
}>({
@@ -26,7 +29,7 @@ export function LaunchBarActionButton({ className, ...props }: Omit
);
@@ -34,6 +37,7 @@ export function LaunchBarActionButton({ className, ...props }: Omit & { icon: string }) {
const { isHorizontalLayout } = useContext(LaunchBarContext);
+ const titlePosition = getTitlePosition(isHorizontalLayout);
return (
}
- titlePosition={isHorizontalLayout ? "bottom" : "right"}
+ titlePosition={titlePosition}
titleOptions={{ animation: false }}
dropdownOptions={{
...dropdownOptions,
popperConfig: {
- placement: isHorizontalLayout ? "bottom" : "right"
+ placement: titlePosition
}
}}
mobileBackdrop
@@ -67,3 +71,10 @@ export function useLauncherIconAndTitle(note: FNote) {
title: title ?? ""
};
}
+
+function getTitlePosition(isHorizontalLayout: boolean) {
+ if (cachedIsMobile) {
+ return "top";
+ }
+ return isHorizontalLayout ? "bottom" : "right";
+}
diff --git a/apps/client/src/widgets/mobile_widgets/sidebar_container.ts b/apps/client/src/widgets/mobile_widgets/sidebar_container.ts
index ef719d36a9..f79d8a72c2 100644
--- a/apps/client/src/widgets/mobile_widgets/sidebar_container.ts
+++ b/apps/client/src/widgets/mobile_widgets/sidebar_container.ts
@@ -13,7 +13,7 @@ const DRAG_OPEN_THRESHOLD = 10;
/** The number of pixels the user has to drag across the screen to the right when the sidebar is closed to trigger the drag open animation. */
const DRAG_CLOSED_START_THRESHOLD = 10;
/** The number of pixels the user has to drag across the screen to the left when the sidebar is opened to trigger the drag close animation. */
-const DRAG_OPENED_START_THRESHOLD = 80;
+const DRAG_OPENED_START_THRESHOLD = 100;
export default class SidebarContainer extends FlexContainer {
private screenName: Screen;
@@ -54,7 +54,7 @@ export default class SidebarContainer extends FlexContainer {
this.startX = x;
// Prevent dragging if too far from the edge of the screen and the menu is closed.
- let dragRefX = glob.isRtl ? this.screenWidth - x : x;
+ const dragRefX = glob.isRtl ? this.screenWidth - x : x;
if (dragRefX > 30 && this.currentTranslate === -100) {
return;
}
@@ -89,7 +89,7 @@ export default class SidebarContainer extends FlexContainer {
}
} else if (this.dragState === DRAG_STATE_DRAGGING) {
const width = this.sidebarEl.offsetWidth;
- let translatePercentage = Math.min(0, Math.max(this.currentTranslate + (deltaX / width) * 100, -100));
+ const translatePercentage = Math.min(0, Math.max(this.currentTranslate + (deltaX / width) * 100, -100));
const backdropOpacity = Math.max(0, 1 + translatePercentage / 100);
this.translatePercentage = translatePercentage;
if (glob.isRtl) {
@@ -160,12 +160,10 @@ export default class SidebarContainer extends FlexContainer {
this.sidebarEl.classList.toggle("show", isOpen);
if (isOpen) {
this.sidebarEl.style.transform = "translateX(0)";
+ } else if (glob.isRtl) {
+ this.sidebarEl.style.transform = "translateX(100%)";
} else {
- if (glob.isRtl) {
- this.sidebarEl.style.transform = "translateX(100%)"
- } else {
- this.sidebarEl.style.transform = "translateX(-100%)";
- }
+ this.sidebarEl.style.transform = "translateX(-100%)";
}
this.sidebarEl.style.transition = this.originalSidebarTransition;
diff --git a/apps/client/src/widgets/mobile_widgets/toggle_sidebar_button.tsx b/apps/client/src/widgets/mobile_widgets/toggle_sidebar_button.tsx
index 8e689954b0..b87e8cb90e 100644
--- a/apps/client/src/widgets/mobile_widgets/toggle_sidebar_button.tsx
+++ b/apps/client/src/widgets/mobile_widgets/toggle_sidebar_button.tsx
@@ -1,5 +1,5 @@
-import ActionButton from "../react/ActionButton";
import { t } from "../../services/i18n";
+import ActionButton from "../react/ActionButton";
import { useNoteContext } from "../react/hooks";
export default function ToggleSidebarButton() {
@@ -10,10 +10,15 @@ export default function ToggleSidebarButton() {
{ noteContext?.isMainContext() && parentComponent?.triggerCommand("setActiveScreen", {
- screen: "tree"
- })}
+ onClick={(e) => {
+ // Remove focus to prevent tooltip showing on top of the sidebar.
+ (e.currentTarget as HTMLButtonElement).blur();
+
+ parentComponent?.triggerCommand("setActiveScreen", {
+ screen: "tree"
+ });
+ }}
/>}
- )
+ );
}
diff --git a/apps/client/src/widgets/note_icon.tsx b/apps/client/src/widgets/note_icon.tsx
index 9df9ad48f4..31ca7e65b4 100644
--- a/apps/client/src/widgets/note_icon.tsx
+++ b/apps/client/src/widgets/note_icon.tsx
@@ -69,7 +69,7 @@ function MobileNoteIconSwitcher({ note, icon }: {
const [ modalShown, setModalShown ] = useState(false);
const { windowWidth } = useWindowSize();
- return (note &&
+ return (
- setModalShown(false)} columnCount={Math.max(1, Math.floor(windowWidth / ICON_SIZE))} />
+ {note && setModalShown(false)} columnCount={Math.max(1, Math.floor(windowWidth / ICON_SIZE))} />}
), document.body)}
diff --git a/apps/client/src/widgets/react/ActionButton.tsx b/apps/client/src/widgets/react/ActionButton.tsx
index feb5972ef4..764e155c44 100644
--- a/apps/client/src/widgets/react/ActionButton.tsx
+++ b/apps/client/src/widgets/react/ActionButton.tsx
@@ -3,6 +3,7 @@ import { useEffect, useRef, useState } from "preact/hooks";
import { CommandNames } from "../../components/app_context";
import keyboard_actions from "../../services/keyboard_actions";
+import { isMobile } from "../../services/utils";
import { useStaticTooltip } from "./hooks";
export interface ActionButtonProps extends Pick, "onClick" | "onAuxClick" | "onContextMenu" | "style"> {
@@ -17,6 +18,8 @@ export interface ActionButtonProps extends Pick(null);
const [ keyboardShortcut, setKeyboardShortcut ] = useState();
@@ -25,6 +28,7 @@ export default function ActionButton({ text, icon, className, triggerCommand, ti
title: keyboardShortcut?.length ? `${text} (${keyboardShortcut?.join(",")})` : text,
placement: titlePosition ?? "bottom",
fallbackPlacements: [ titlePosition ?? "bottom" ],
+ trigger: cachedIsMobile ? "focus" : "hover focus",
animation: false
});
diff --git a/apps/client/src/widgets/react/Button.tsx b/apps/client/src/widgets/react/Button.tsx
index 1aab2153e6..6269000563 100644
--- a/apps/client/src/widgets/react/Button.tsx
+++ b/apps/client/src/widgets/react/Button.tsx
@@ -1,13 +1,14 @@
-import type { ComponentChildren, RefObject } from "preact";
-import type { CSSProperties } from "preact/compat";
+import type { ComponentChildren, CSSProperties, RefObject } from "preact";
import { memo } from "preact/compat";
import { useMemo } from "preact/hooks";
import { CommandNames } from "../../components/app_context";
-import { isDesktop } from "../../services/utils";
+import { isDesktop, isMobile } from "../../services/utils";
import ActionButton from "./ActionButton";
import Icon from "./Icon";
+const cachedIsMobile = isMobile();
+
export interface ButtonProps {
name?: string;
/** Reference to the button element. Mostly useful for requesting focus. */
@@ -30,7 +31,7 @@ const Button = memo(({ name, buttonRef, className, text, onClick, keyboardShortc
// Memoize classes array to prevent recreation
const classes = useMemo(() => {
const classList: string[] = ["btn"];
-
+
switch(kind) {
case "primary":
classList.push("btn-primary");
@@ -42,7 +43,7 @@ const Button = memo(({ name, buttonRef, className, text, onClick, keyboardShortc
classList.push("btn-secondary");
break;
}
-
+
if (className) {
classList.push(className);
}
@@ -56,7 +57,7 @@ const Button = memo(({ name, buttonRef, className, text, onClick, keyboardShortc
// Memoize keyboard shortcut rendering
const shortcutElements = useMemo(() => {
- if (!keyboardShortcut) return null;
+ if (!keyboardShortcut || cachedIsMobile) return null;
const splitShortcut = keyboardShortcut.split("+");
return splitShortcut.map((key, index) => (
<>