Files
plainleaf/client/reducer.ts
T
Zef Hemel 1b0ba027b3 Add standalone option to action buttons
When `standalone` is set to true, this action button will only appear in
"standalone PWA" mode (e.g. home-screen mobile apps, or installed PWA on
desktop). Useful to e.g. only show forward and backward buttons. These
forward and backward buttons are now also added to the default action
button config.
2026-03-12 14:51:31 +01:00

234 lines
5.8 KiB
TypeScript

import type { Action, AppViewState } from "./types/ui.ts";
import type { PageMeta } from "../plug-api/types/index.ts";
import {
isMarkdownPath,
parseToRef,
} from "@silverbulletmd/silverbullet/lib/ref";
export default function reducer(
state: AppViewState,
action: Action,
): AppViewState {
switch (action.type) {
case "document-editor-loaded":
return {
...state,
isLoading: false,
current: {
path: action.path,
meta: action.meta,
},
};
case "page-loaded": {
const mouseDetected = globalThis.matchMedia("(pointer:fine)").matches;
const isBrowser = globalThis.matchMedia("(display-mode: browser)")
.matches;
return {
...state,
isLoading: false,
isMobile: !mouseDetected,
isStandalone: !isBrowser,
current: {
path: action.path,
meta: action.meta as PageMeta,
},
};
}
case "document-editor-changed":
case "page-changed":
return {
...state,
unsavedChanges: true,
};
case "document-editor-saved":
case "page-saved": {
return {
...state,
unsavedChanges: false,
};
}
case "update-current-page-meta": {
// Update in the allPages list as well
state.allPages = state.allPages.map((pageMeta) =>
pageMeta.name === action.meta.name
? { ...action.meta, lastOpened: Date.now() }
: pageMeta,
);
// Can't update page meta if not on a page
if (!state.current || !isMarkdownPath(state.current.path)) {
return state;
}
return {
...state,
current: {
...state.current,
meta: action.meta,
},
};
}
case "online-status-change":
return {
...state,
isOnline: action.isOnline,
};
case "update-page-list": {
// Let's move over any "lastOpened" times to the "allPages" list
const oldPageMeta = new Map(
[...state.allPages].map((pm) => [pm.name, pm]),
);
let currPageMeta: PageMeta | undefined;
for (const pageMeta of action.allPages) {
const oldPageMetaItem = oldPageMeta.get(pageMeta.name);
if (oldPageMetaItem?.lastOpened) {
pageMeta.lastOpened = oldPageMetaItem.lastOpened;
}
if (parseToRef(pageMeta.name)?.path === state.current?.path) {
currPageMeta = pageMeta;
}
}
const newState = {
...state,
allPages: action.allPages,
};
if (currPageMeta) {
newState.current!.meta = currPageMeta;
}
return newState;
}
case "update-document-list": {
return {
...state,
allDocuments: action.allDocuments,
};
}
case "start-navigate": {
return {
...state,
showPageNavigator: true,
pageNavigatorMode: action.mode,
showCommandPalette: false,
showFilterBox: false,
};
}
case "stop-navigate":
return {
...state,
showPageNavigator: false,
};
case "show-palette": {
return {
...state,
showCommandPalette: true,
showPageNavigator: false,
showFilterBox: false,
showCommandPaletteContext: action.context,
commands: action.commands,
};
}
case "hide-palette":
return {
...state,
showCommandPalette: false,
showCommandPaletteContext: undefined,
};
case "update-commands":
return {
...state,
commands: action.commands,
};
case "show-notification":
return {
...state,
notifications: [...state.notifications, action.notification],
};
case "dismiss-notification":
return {
...state,
notifications: state.notifications.filter((n) => n.id !== action.id),
};
case "show-panel":
return {
...state,
panels: {
...state.panels,
[action.id]: action.config,
},
};
case "hide-panel":
return {
...state,
panels: {
...state.panels,
[action.id]: {},
},
};
case "show-filterbox":
return {
...state,
showFilterBox: true,
filterBoxOnSelect: action.onSelect,
filterBoxPlaceHolder: action.placeHolder,
filterBoxOptions: action.options,
filterBoxLabel: action.label,
filterBoxHelpText: action.helpText,
};
case "hide-filterbox":
return {
...state,
showCommandPalette: false,
showPageNavigator: false,
showFilterBox: false,
filterBoxOnSelect: () => {},
filterBoxPlaceHolder: "",
filterBoxOptions: [],
filterBoxHelpText: "",
};
case "show-prompt":
return {
...state,
showPrompt: true,
promptDefaultValue: action.defaultValue,
promptMessage: action.message,
promptCallback: action.callback,
};
case "hide-prompt":
return {
...state,
showPrompt: false,
promptDefaultValue: undefined,
promptMessage: undefined,
promptCallback: undefined,
};
case "show-confirm":
return {
...state,
showConfirm: true,
confirmMessage: action.message,
confirmCallback: action.callback,
};
case "hide-confirm":
return {
...state,
showConfirm: false,
confirmMessage: undefined,
confirmCallback: undefined,
};
case "set-ui-option":
return {
...state,
uiOptions: {
...state.uiOptions,
[action.key]: action.value,
},
};
case "set-progress":
return {
...state,
progressPercentage: action.progressPercentage,
progressType: action.progressType,
};
}
}