* feat: initial base structure * feat: utils for constructing and flattening collection tree * feat: basic demo to display tree-like structure with virtualization * feat: make it searchable * feat: row component * fix: handle row selection * fix: scroll jitter * fix: popover max-height to eliminate extra scroll * fix: position scrollbar correctly * fix: do not sort to maintain correct tree-like view * feat: footer * fix: scroll to selected item * fix: deselect item * fix: display selected location in footer * fix: deselect item if any upon search trigger * fix: create draft without collection * fix: pass down collectionId to all the nodes * feat: publish document under selected location * fix: move the doc post publish in case it is supposed to be a nested doc * fix: wrap text for selected location * fix: footer background in dark mode and unused css * fix: popover height in small devices * fix: no need to spread * refactor: remove outline * refactor: border-radius is common * refactor: remove active and focus * fix: do not shrink spacer * fix: scroll list padding with correctly adjusted scrolling * refactor: use constants * fix: use padding in favor of spacer * refactor: border attrs not needed * refactor: control title padding and icon size centrally * fix: rename param * fix: import path * fix: refactor styles, avoid magic numbers * fix: type err * feat: make rows collapsible * fix: fully expanded without disclosure upon search * fix: use modal in place of popover * fix: collapse descendants * fix: rename PublishPopover to PublishModal * fix: adjust collapse icon as part of tree view * fix: enable keyboard navigation * not sure why collapse and expand shortcuts are not working * fix: row expansion and search box focus and blur * fix: remove css hover, handle it via active prop * fix: discard tree like view for search results * fix: minor tweaks * refactor: no need to pass onPublish * refactor: remove unnecessary attrs from search component * fix: publish button text * fix: reset intial scroll offset to 0 on search * fix: remove search highlights * fix: clean up search component * refactor: search and row collapse * refactor: PublishLocation * fix: show emoji or star icon if present * fix: shift focus only from top item * fix: leading emoji * fix: baseline text * fix: make path tertiary * fix: do not show path for collections * fix: path text color upon selection * fix: deleted collection case * fix: no results found * fix: space around slash * Refinement, some small refactors * fix: Publish shortcut, use Button action * Allow new document creation from command menu without active collection * fix: duplicate * fix: Unneccessary truncation * fix: Scroll on expand/collapse Remove wraparound * fix: tsc * fix: Horizontal overflow on PublishLocation Remove pointless moveTo method * fix: Missing translation * Remove method indirection Show expanded collection icon in tree when expanded * Shrink font size a point * Remove feature flag * fix: Path color contrast in light mode Remove unused expanded/show attributes * shrink -> collapse, fix expanded disclosure without items after searching * Mobile styles * fix: scroll just into view Co-authored-by: Tom Moor <tom.moor@gmail.com>
217 lines
4.7 KiB
TypeScript
217 lines
4.7 KiB
TypeScript
import { Location, LocationDescriptor } from "history";
|
|
import { TFunction } from "i18next";
|
|
import RootStore from "~/stores/RootStore";
|
|
import Document from "./models/Document";
|
|
import FileOperation from "./models/FileOperation";
|
|
import Pin from "./models/Pin";
|
|
import Star from "./models/Star";
|
|
|
|
export type PartialWithId<T> = Partial<T> & { id: string };
|
|
|
|
export type MenuItemButton = {
|
|
type: "button";
|
|
title: React.ReactNode;
|
|
onClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
|
|
dangerous?: boolean;
|
|
visible?: boolean;
|
|
selected?: boolean;
|
|
disabled?: boolean;
|
|
icon?: React.ReactElement;
|
|
};
|
|
|
|
export type MenuItemWithChildren = {
|
|
type: "submenu";
|
|
title: React.ReactNode;
|
|
visible?: boolean;
|
|
disabled?: boolean;
|
|
style?: React.CSSProperties;
|
|
hover?: boolean;
|
|
|
|
items: MenuItem[];
|
|
icon?: React.ReactElement;
|
|
};
|
|
|
|
export type MenuSeparator = {
|
|
type: "separator";
|
|
visible?: boolean;
|
|
};
|
|
|
|
export type MenuHeading = {
|
|
type: "heading";
|
|
visible?: boolean;
|
|
title: React.ReactNode;
|
|
};
|
|
|
|
export type MenuInternalLink = {
|
|
type: "route";
|
|
title: React.ReactNode;
|
|
to: LocationDescriptor;
|
|
visible?: boolean;
|
|
selected?: boolean;
|
|
disabled?: boolean;
|
|
icon?: React.ReactElement;
|
|
};
|
|
|
|
export type MenuExternalLink = {
|
|
type: "link";
|
|
title: React.ReactNode;
|
|
href: string;
|
|
visible?: boolean;
|
|
selected?: boolean;
|
|
disabled?: boolean;
|
|
level?: number;
|
|
icon?: React.ReactElement;
|
|
};
|
|
|
|
export type MenuItem =
|
|
| MenuInternalLink
|
|
| MenuItemButton
|
|
| MenuExternalLink
|
|
| MenuItemWithChildren
|
|
| MenuSeparator
|
|
| MenuHeading;
|
|
|
|
export type ActionContext = {
|
|
isContextMenu: boolean;
|
|
isCommandBar: boolean;
|
|
isButton: boolean;
|
|
inStarredSection?: boolean;
|
|
activeCollectionId: string | undefined;
|
|
activeDocumentId: string | undefined;
|
|
currentUserId: string | undefined;
|
|
currentTeamId: string | undefined;
|
|
location: Location;
|
|
stores: RootStore;
|
|
event?: Event;
|
|
t: TFunction;
|
|
};
|
|
|
|
export type Action = {
|
|
type?: undefined;
|
|
id: string;
|
|
name: ((context: ActionContext) => string) | string;
|
|
section: ((context: ActionContext) => string) | string;
|
|
shortcut?: string[];
|
|
keywords?: string;
|
|
dangerous?: boolean;
|
|
iconInContextMenu?: boolean;
|
|
icon?: React.ReactElement | React.FC;
|
|
placeholder?: ((context: ActionContext) => string) | string;
|
|
selected?: (context: ActionContext) => boolean;
|
|
visible?: (context: ActionContext) => boolean;
|
|
perform?: (context: ActionContext) => Promise<any> | any;
|
|
children?: ((context: ActionContext) => Action[]) | Action[];
|
|
};
|
|
|
|
export type CommandBarAction = {
|
|
id: string;
|
|
name: string;
|
|
section?: string;
|
|
shortcut: string[];
|
|
keywords: string;
|
|
placeholder?: string;
|
|
icon?: React.ReactElement;
|
|
perform?: () => void;
|
|
children?: string[];
|
|
parent?: string;
|
|
};
|
|
|
|
export type LocationWithState = Location & {
|
|
state: Record<string, string>;
|
|
};
|
|
|
|
export type Toast = {
|
|
id: string;
|
|
createdAt: string;
|
|
message: string;
|
|
type: "warning" | "error" | "info" | "success" | "loading";
|
|
timeout?: number;
|
|
reoccurring?: number;
|
|
action?: {
|
|
text: string;
|
|
onClick: React.MouseEventHandler<HTMLSpanElement>;
|
|
};
|
|
};
|
|
|
|
export type FetchOptions = {
|
|
prefetch?: boolean;
|
|
revisionId?: string;
|
|
shareId?: string;
|
|
force?: boolean;
|
|
};
|
|
|
|
export type NavigationNode = {
|
|
id: string;
|
|
title: string;
|
|
url: string;
|
|
children: NavigationNode[];
|
|
isDraft?: boolean;
|
|
};
|
|
|
|
export type CollectionSort = {
|
|
field: string;
|
|
direction: "asc" | "desc";
|
|
};
|
|
|
|
// Pagination response in an API call
|
|
export type Pagination = {
|
|
limit: number;
|
|
nextPath: string;
|
|
offset: number;
|
|
};
|
|
|
|
// Pagination request params
|
|
export type PaginationParams = {
|
|
limit?: number;
|
|
offset?: number;
|
|
sort?: string;
|
|
direction?: "ASC" | "DESC";
|
|
};
|
|
|
|
export type SearchResult = {
|
|
id: string;
|
|
ranking: number;
|
|
context: string;
|
|
document: Document;
|
|
};
|
|
|
|
export type ToastOptions = {
|
|
type: "warning" | "error" | "info" | "success" | "loading";
|
|
timeout?: number;
|
|
action?: {
|
|
text: string;
|
|
onClick: React.MouseEventHandler<HTMLSpanElement>;
|
|
};
|
|
};
|
|
|
|
export type WebsocketEntityDeletedEvent = {
|
|
modelId: string;
|
|
};
|
|
|
|
export type WebsocketEntitiesEvent = {
|
|
documentIds: { id: string; updatedAt?: string }[];
|
|
collectionIds: { id: string; updatedAt?: string }[];
|
|
groupIds: { id: string; updatedAt?: string }[];
|
|
teamIds: string[];
|
|
event: string;
|
|
};
|
|
|
|
export type WebsocketCollectionUserEvent = {
|
|
collectionId: string;
|
|
userId: string;
|
|
};
|
|
|
|
export type WebsocketCollectionUpdateIndexEvent = {
|
|
collectionId: string;
|
|
index: string;
|
|
};
|
|
|
|
export type WebsocketEvent =
|
|
| PartialWithId<Pin>
|
|
| PartialWithId<Star>
|
|
| PartialWithId<FileOperation>
|
|
| WebsocketCollectionUserEvent
|
|
| WebsocketCollectionUpdateIndexEvent
|
|
| WebsocketEntityDeletedEvent
|
|
| WebsocketEntitiesEvent;
|