Skip to content

Commit

Permalink
Merge branch 'master' into theme-customization
Browse files Browse the repository at this point in the history
  • Loading branch information
RvanderLaan committed Apr 9, 2022
2 parents a61a1e8 + 7df0402 commit 66a6e37
Show file tree
Hide file tree
Showing 24 changed files with 281 additions and 405 deletions.
4 changes: 2 additions & 2 deletions resources/style/content.scss
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@
}

.image-loading {
width: var(--thumbnail-size, 100px);
height: var(--thumbnail-size, 100px);
width: 2rem;
aspect-ratio: 1 / 1;
margin: auto;
border-radius: 50%;
border: 0.25rem solid var(--background-color);
Expand Down
6 changes: 4 additions & 2 deletions src/frontend/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useStore } from './contexts/StoreContext';
import ErrorBoundary from './containers/ErrorBoundary';
import ContentView from './containers/ContentView';
import { IconSet, Toggle } from 'widgets';
import { Toolbar, ToolbarButton } from 'widgets/menus';
import { ContextMenuLayer, Toolbar, ToolbarButton } from 'widgets/menus';

import { useWorkerListener } from './image/ThumbnailGeneration';
import SplashScreen from './containers/SplashScreen';
Expand Down Expand Up @@ -77,7 +77,9 @@ const PreviewApp = observer(() => {
/>
</Toolbar>

<ContentView />
<ContextMenuLayer>
<ContentView />
</ContextMenuLayer>
</ErrorBoundary>
</div>
);
Expand Down
17 changes: 0 additions & 17 deletions src/frontend/components/ContextMenu.tsx

This file was deleted.

45 changes: 18 additions & 27 deletions src/frontend/components/FileTag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ import { IconSet } from 'widgets/Icons';
import { Row } from 'widgets';
import { useStore } from '../contexts/StoreContext';
import { TagSelector } from './TagSelector';
import useContextMenu from '../hooks/useContextMenu';
import { FileTagMenuItems } from '../containers/ContentView/menu-items';
import { ClientTag } from 'src/entities/Tag';
import { Menu } from 'widgets/menus';
import ContextMenu from './ContextMenu';
import { Menu, useContextMenu } from 'widgets/menus';

interface IFileTagProp {
file: ClientFile;
Expand All @@ -18,8 +16,6 @@ interface IFileTagProp {
const FileTags = observer(({ file }: IFileTagProp) => {
const { tagStore } = useStore();

const [contextState, { show, hide }] = useContextMenu();

const renderCreateOption = useCallback(
(tagName: string, resetTextBox: () => void) => (
<Row
Expand All @@ -37,37 +33,32 @@ const FileTags = observer(({ file }: IFileTagProp) => {
[file, tagStore],
);

const show = useContextMenu();
const handleTagContextMenu = useCallback(
(event: React.MouseEvent<HTMLElement>, tag: ClientTag) => {
event.stopPropagation();
show(event.clientX, event.clientY, [
<React.Fragment key="file-tag-context-menu">
show(
event.clientX,
event.clientY,
<Menu>
<FileTagMenuItems file={file} tag={tag} />
</React.Fragment>,
]);
</Menu>,
);
},
[file, show],
);

return (
<>
<TagSelector
disabled={file.isBroken}
selection={Array.from(file.tags)}
onClear={file.clearTags}
onDeselect={file.removeTag}
onSelect={file.addTag}
renderCreateOption={renderCreateOption}
showTagContextMenu={handleTagContextMenu}
multiline
/>

{/* TODO: probably not the right place for the ContextMenu component.
Why not a single one at the root element that can be interacted with through a Context? */}
<ContextMenu isOpen={contextState.open} x={contextState.x} y={contextState.y} close={hide}>
<Menu>{contextState.menu}</Menu>
</ContextMenu>
</>
<TagSelector
disabled={file.isBroken}
selection={Array.from(file.tags)}
onClear={file.clearTags}
onDeselect={file.removeTag}
onSelect={file.addTag}
renderCreateOption={renderCreateOption}
showTagContextMenu={handleTagContextMenu}
multiline
/>
);
});

Expand Down
3 changes: 2 additions & 1 deletion src/frontend/components/PopupWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ const PopupWindow: React.FC<IPopupWindowProps> = (props) => {
if (win) {
return ReactDOM.createPortal(
<>
{props.children} <Overlay document={win.document} />
{props.children}
<Overlay document={win.document} />
</>,
containerEl,
);
Expand Down
12 changes: 8 additions & 4 deletions src/frontend/components/TagSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,14 @@ const TagSelector = (props: TagSelectorProps) => {
setQuery(e.target.value);
}).current;

const clearSelection = useCallback(() => {
setQuery('');
onClear();
}, [onClear]);
const clearSelection = useCallback(
(e: React.MouseEvent) => {
e.stopPropagation();
setQuery('');
onClear();
},
[onClear],
);

const isInputEmpty = query.length === 0;

Expand Down
4 changes: 3 additions & 1 deletion src/frontend/containers/AppToolbar/Searchbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ const QuickSearchList = observer(() => {
const SearchMatchButton = observer(({ disabled }: { disabled: boolean }) => {
const { fileStore, uiStore } = useStore();

const handleClick = useRef(() => {
const handleClick = useRef((e: React.MouseEvent) => {
e.stopPropagation();
uiStore.toggleSearchMatchAny();
fileStore.refetch();
}).current;
Expand Down Expand Up @@ -148,6 +149,7 @@ const CriteriaList = observer(() => {
fileStore.refetch();
e.stopPropagation();
e.preventDefault();
// TODO: search input element keeps focus after click???
}}
className="btn-icon-large"
/>
Expand Down
61 changes: 48 additions & 13 deletions src/frontend/containers/ContentView/Commands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { ClientTag } from 'src/entities/Tag';
import { useStore } from 'src/frontend/contexts/StoreContext';
import { DnDAttribute, DnDTagType, useTagDnD } from 'src/frontend/contexts/TagDnDContext';
import { RendererMessenger } from 'src/Messaging';
import { MenuDivider } from 'widgets/menus';
import { IconSet } from 'widgets/Icons';
import { Menu, MenuDivider, MenuSubItem, useContextMenu } from 'widgets/menus';
import { LayoutMenuItems, SortMenuItems } from '../AppToolbar/Menus';
import {
ExternalAppMenuItems,
FileTagMenuItems,
Expand Down Expand Up @@ -142,12 +144,36 @@ export class CommandDispatcher {

export function useCommandHandler(
select: (file: ClientFile, selectAdditive: boolean, selectRange: boolean) => void,
showContextMenu: (x: number, y: number, menu: [JSX.Element, JSX.Element]) => void,
) {
const dndData = useTagDnD();
const { uiStore } = useStore();
const show = useContextMenu();

useEffect(() => {
const showContextMenu = (
x: number,
y: number,
fileMenu: JSX.Element,
externalMenu: JSX.Element,
) => {
show(
x,
y,
<Menu>
{fileMenu}
<MenuDivider />
<MenuSubItem icon={IconSet.VIEW_GRID} text="View method...">
<LayoutMenuItems />
</MenuSubItem>
<MenuSubItem icon={IconSet.FILTER_NAME_DOWN} text="Sort by...">
<SortMenuItems />
</MenuSubItem>
<MenuDivider />
{externalMenu}
</Menu>,
);
};

const handleSelect = action((event: Event) => {
event.stopPropagation();
const { file, selectAdditive, selectRange } = (event as CommandHandlerEvent<SelectPayload>)
Expand All @@ -167,10 +193,12 @@ export function useCommandHandler(
const handleContextMenu = action((event: Event) => {
event.stopPropagation();
const { file, x, y } = (event as CommandHandlerEvent<ContextMenuPayload>).detail;
showContextMenu(x, y, [
showContextMenu(
x,
y,
file.isBroken ? <MissingFileMenuItems /> : <FileViewerMenuItems file={file} />,
<ExternalAppMenuItems key="external" file={file} />,
]);
<ExternalAppMenuItems file={file} />,
);
if (!uiStore.fileSelection.has(file)) {
// replace selection with context menu, like Windows file explorer
select(file, false, false);
Expand All @@ -180,14 +208,16 @@ export function useCommandHandler(
const handleTagContextMenu = action((event: Event) => {
event.stopPropagation();
const { file, x, y, tag } = (event as CommandHandlerEvent<TagContextMenuPayload>).detail;
showContextMenu(x, y, [
showContextMenu(
x,
y,
<>
<FileTagMenuItems file={file} tag={tag} />
<MenuDivider />
{file.isBroken ? <MissingFileMenuItems /> : <FileViewerMenuItems file={file} />}
</>,
<ExternalAppMenuItems key="external" file={file} />,
]);
<ExternalAppMenuItems file={file} />,
);
if (!uiStore.fileSelection.has(file)) {
// replace selection with context menu, like Windows file explorer
select(file, false, false);
Expand All @@ -197,10 +227,15 @@ export function useCommandHandler(
const handleSlideContextMenu = action((event: Event) => {
event.stopPropagation();
const { file, x, y } = (event as CommandHandlerEvent<ContextMenuPayload>).detail;
showContextMenu(x, y, [
file.isBroken ? <MissingFileMenuItems /> : <SlideFileViewerMenuItems file={file} />,
<ExternalAppMenuItems key="external" file={file} />,
]);
show(
x,
y,
<Menu>
{file.isBroken ? <MissingFileMenuItems /> : <SlideFileViewerMenuItems file={file} />}
<MenuDivider />
<ExternalAppMenuItems file={file} />
</Menu>,
);
if (!uiStore.fileSelection.has(file)) {
// replace selection with context menu, like Windows file explorer
select(file, false, false);
Expand Down Expand Up @@ -275,7 +310,7 @@ export function useCommandHandler(
el.removeEventListener(Selector.FileDragLeave, handleDragLeave, true);
el.removeEventListener(Selector.FileDrop, handleDrop, true);
};
}, [uiStore, dndData, select, showContextMenu]);
}, [uiStore, dndData, select, show]);
}

/**
Expand Down
6 changes: 1 addition & 5 deletions src/frontend/containers/ContentView/GalleryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,16 +193,12 @@ const TagWithHint = observer(
tag: ClientTag;
onContextMenu: (e: MousePointerEvent, tag: ClientTag) => void;
}) => {
const handleContextMenu = useCallback(
(e: React.MouseEvent<HTMLElement>) => onContextMenu(e, tag),
[onContextMenu, tag],
);
return (
<Tag
text={tag.name}
color={tag.viewColor}
tooltip={tag.path.join(' › ')}
onContextMenu={handleContextMenu}
onContextMenu={(e) => onContextMenu(e, tag)}
/>
);
},
Expand Down
5 changes: 2 additions & 3 deletions src/frontend/containers/ContentView/LayoutSwitcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ import { ContentRect } from './utils';

interface LayoutProps {
contentRect: ContentRect;
showContextMenu: (x: number, y: number, menu: [JSX.Element, JSX.Element]) => void;
}

const Layout = ({ contentRect, showContextMenu }: LayoutProps) => {
const Layout = ({ contentRect }: LayoutProps) => {
const { fileStore, uiStore } = useStore();

// Todo: Select by dragging a rectangle shape
Expand Down Expand Up @@ -121,7 +120,7 @@ const Layout = ({ contentRect, showContextMenu }: LayoutProps) => {
return () => window.clearTimeout(handle);
}, [isSlideMode]);

useCommandHandler(handleFileSelect, showContextMenu);
useCommandHandler(handleFileSelect);

if (contentRect.width < 10) {
return null;
Expand Down
47 changes: 46 additions & 1 deletion src/frontend/containers/ContentView/Placeholder.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { observer } from 'mobx-react-lite';
import LOGO_FC from 'resources/logo/svg/full-color/allusion-logomark-fc.svg';
import { IS_PREVIEW_WINDOW } from 'common/window';

import { useStore } from '../../contexts/StoreContext';

const Placeholder = observer(() => {
const { fileStore, tagStore } = useStore();

if (IS_PREVIEW_WINDOW) {
return <PreviewWindowPlaceholder />;
}
if (fileStore.showsAllContent && tagStore.isEmpty) {
// No tags exist, and no images added: Assuming it's a new user -> Show a welcome screen
return <Welcome />;
Expand All @@ -26,6 +30,47 @@ const Placeholder = observer(() => {
export default Placeholder;

import { IconSet, Button, ButtonGroup, SVG } from 'widgets';
import { RendererMessenger } from 'src/Messaging';
import useMountState from 'src/frontend/hooks/useMountState';

const PreviewWindowPlaceholder = observer(() => {
const { fileStore } = useStore();
const [isLoading, setIsLoading] = useState(true);
const [, isMounted] = useMountState();
useEffect(() => {
setIsLoading(true);
setTimeout(() => {
if (isMounted.current) {
setIsLoading(false);
}
}, 1000);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fileStore.fileListLastModified]);

if (isLoading) {
return (
<ContentPlaceholder title="Loading..." icon={<SVG src={LOGO_FC} />}>
{IconSet.LOADING}
</ContentPlaceholder>
);
}

// There should always be images to preview.
// If the placeholder is shown, something went wrong (probably the DB of the preview window is out of sync with the main window)
return (
<ContentPlaceholder title="That's not supposed to happen..." icon={<SVG src={LOGO_FC} />}>
<p>Something went wrong while previewing the selected images</p>

<div className="divider" />

<Button
styling="outlined"
text="Reload Allusion"
onClick={() => RendererMessenger.reload()}
/>
</ContentPlaceholder>
);
});

const Welcome = () => {
const { uiStore } = useStore();
Expand Down
Loading

0 comments on commit 66a6e37

Please sign in to comment.