Improve mobile navigation through history (#686)

* History back and forward commands
* Conditionally display actionButtons on mobile devices
pull/690/head
Marek S. Łukasiewicz 2024-02-07 09:33:47 +01:00 committed by GitHub
parent bfd8ef9cd2
commit 257c7a3e4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 47 additions and 4 deletions

View File

@ -73,6 +73,15 @@ export function openUrl(url: string, existingWindow = false): Promise<void> {
return syscall("editor.openUrl", url, existingWindow); return syscall("editor.openUrl", url, existingWindow);
} }
/**
* This is calling the `go()` method from the History Web API.
* @param delta Position in history to move to relative to the current page,
* where a negative value moves backwards, and positive forwards
*/
export function goHistory(delta: number): Promise<void> {
return syscall("editor.goHistory", delta);
}
// Force the client to download the file in dataUrl with filename as file name // Force the client to download the file in dataUrl with filename as file name
export function downloadFile(filename: string, dataUrl: string): Promise<void> { export function downloadFile(filename: string, dataUrl: string): Promise<void> {
return syscall("editor.downloadFile", filename, dataUrl); return syscall("editor.downloadFile", filename, dataUrl);

View File

@ -89,6 +89,14 @@ functions:
command: command:
name: "Navigate: To URL" name: "Navigate: To URL"
hide: true hide: true
navigateBack:
path: "./navigate.ts:navigateBack"
command:
name: "Navigate: Back in History"
navigateForward:
path: "./navigate.ts:navigateForward"
command:
name: "Navigate: Forward in History"
# Text editing commands # Text editing commands
quoteSelectionCommand: quoteSelectionCommand:
@ -185,7 +193,6 @@ functions:
path: ./embed.ts:embedWidget path: ./embed.ts:embedWidget
codeWidget: embed codeWidget: embed
# Vim # Vim
toggleVimMode: toggleVimMode:
path: "./vim.ts:toggleVimMode" path: "./vim.ts:toggleVimMode"
@ -302,4 +309,4 @@ functions:
name: "Flash: Custom Message" name: "Flash: Custom Message"
hide: true hide: true
contexts: contexts:
- internal - internal

View File

@ -140,3 +140,11 @@ export async function navigateToPage(_cmdDef: any, pageName: string) {
export async function navigateToURL(_cmdDef: any, url: string) { export async function navigateToURL(_cmdDef: any, url: string) {
await editor.openUrl(url, false); await editor.openUrl(url, false);
} }
export async function navigateBack() {
await editor.goHistory(-1);
}
export async function navigateForward() {
await editor.goHistory(1);
}

View File

@ -10,6 +10,7 @@ export type ActionButton = {
class?: string; class?: string;
callback: () => void; callback: () => void;
href?: string; href?: string;
mobile?: boolean;
}; };
export function TopBar({ export function TopBar({
@ -17,6 +18,7 @@ export function TopBar({
unsavedChanges, unsavedChanges,
syncFailures, syncFailures,
isLoading, isLoading,
isMobile,
notifications, notifications,
onRename, onRename,
actionButtons, actionButtons,
@ -32,6 +34,7 @@ export function TopBar({
unsavedChanges: boolean; unsavedChanges: boolean;
syncFailures: number; syncFailures: number;
isLoading: boolean; isLoading: boolean;
isMobile: boolean;
notifications: Notification[]; notifications: Notification[];
darkMode: boolean; darkMode: boolean;
vimMode: boolean; vimMode: boolean;

View File

@ -192,6 +192,7 @@ export class MainUI {
syncFailures={viewState.syncFailures} syncFailures={viewState.syncFailures}
unsavedChanges={viewState.unsavedChanges} unsavedChanges={viewState.unsavedChanges}
isLoading={viewState.isLoading} isLoading={viewState.isLoading}
isMobile={viewState.isMobile}
vimMode={viewState.uiOptions.vimMode} vimMode={viewState.uiOptions.vimMode}
darkMode={viewState.uiOptions.darkMode} darkMode={viewState.uiOptions.darkMode}
progressPerc={viewState.progressPerc} progressPerc={viewState.progressPerc}
@ -248,7 +249,9 @@ export class MainUI {
}, },
}] }]
: [], : [],
...viewState.settings.actionButtons.map((button) => { ...viewState.settings.actionButtons
.filter((button) => (typeof button.mobile === "undefined") || (button.mobile === viewState.isMobile))
.map((button) => {
const parsedCommand = parseCommand(button.command); const parsedCommand = parseCommand(button.command);
let featherIcon = let featherIcon =
(featherIcons as any)[kebabToCamel(button.icon)]; (featherIcons as any)[kebabToCamel(button.icon)];

View File

@ -18,10 +18,12 @@ export default function reducer(
bottom: {}, bottom: {},
}, },
}; };
case "page-loaded": case "page-loaded": {
const mouseDetected = window.matchMedia("(any-pointer:fine)").matches;
return { return {
...state, ...state,
isLoading: false, isLoading: false,
isMobile: !mouseDetected,
allPages: state.allPages.map((pageMeta) => allPages: state.allPages.map((pageMeta) =>
pageMeta.name === action.meta.name pageMeta.name === action.meta.name
? { ...pageMeta, lastOpened: Date.now() } ? { ...pageMeta, lastOpened: Date.now() }
@ -30,6 +32,7 @@ export default function reducer(
currentPage: action.meta.name, currentPage: action.meta.name,
currentPageMeta: action.meta, currentPageMeta: action.meta,
}; };
}
case "page-changed": case "page-changed":
return { return {
...state, ...state,

View File

@ -73,6 +73,9 @@ export function editorSyscalls(client: Client): SysCallMapping {
location.href = url; location.href = url;
} }
}, },
"editor.goHistory": (_ctx, delta: number) => {
window.history.go(delta);
},
"editor.downloadFile": (_ctx, filename: string, dataUrl: string) => { "editor.downloadFile": (_ctx, filename: string, dataUrl: string) => {
const link = document.createElement("a"); const link = document.createElement("a");
link.href = dataUrl; link.href = dataUrl;

View File

@ -32,6 +32,7 @@ export type ActionButton = {
description?: string; description?: string;
command: string; command: string;
args?: any[]; args?: any[];
mobile?: boolean;
}; };
export type EmojiConfig = { export type EmojiConfig = {
@ -62,6 +63,7 @@ export type AppViewState = {
allPages: PageMeta[]; allPages: PageMeta[];
isLoading: boolean; isLoading: boolean;
isMobile: boolean;
showPageNavigator: boolean; showPageNavigator: boolean;
showCommandPalette: boolean; showCommandPalette: boolean;
showCommandPaletteContext?: string; showCommandPaletteContext?: string;
@ -116,6 +118,7 @@ export const initialViewState: AppViewState = {
darkMode: false, darkMode: false,
forcedROMode: false, forcedROMode: false,
}, },
isMobile: false,
panels: { panels: {
lhs: {}, lhs: {},
rhs: {}, rhs: {},

View File

@ -27,6 +27,10 @@ actionButtons:
- icon: terminal - icon: terminal
command: "{[Open Command Palette]}" command: "{[Open Command Palette]}"
description: Run command description: Run command
- icon: arrow-left
command: "{[Navigate: Back in History]}"
description: "Go to the previous page"
mobile: true # Only show on mobile devices, set to false to show only on desktop
# Override keyboard shortcuts and command priority # Override keyboard shortcuts and command priority
shortcuts: shortcuts: