mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-18 21:36:56 -04:00
[ENG-631] TopBar improvements & misc fixes (#837)
* fix things * added back/forward buttons to settings * split top bar context into left and right * hook up path * fix background jobs hidden from job manager * core * fix type + quick preview transition * fix selected item color contrast * fix close button on quick preview * clean up job ui for light theme * Improve media view overscan --------- Co-authored-by: Brendan Allan <brendonovich@outlook.com>
This commit is contained in:
@@ -1,22 +1,30 @@
|
||||
import { RefObject, createContext, useRef } from 'react';
|
||||
import { RefObject, createContext, useContext, useRef } from 'react';
|
||||
import { Outlet } from 'react-router';
|
||||
import TopBar from '.';
|
||||
|
||||
interface TopBarContext {
|
||||
topBarChildrenRef: RefObject<HTMLDivElement> | null;
|
||||
left: RefObject<HTMLDivElement>;
|
||||
right: RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
export const TopBarContext = createContext<TopBarContext>({
|
||||
topBarChildrenRef: null
|
||||
});
|
||||
const TopBarContext = createContext<TopBarContext | null>(null);
|
||||
|
||||
export const Component = () => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const left = useRef<HTMLDivElement>(null);
|
||||
const right = useRef<HTMLDivElement>(null);
|
||||
|
||||
return (
|
||||
<TopBarContext.Provider value={{ topBarChildrenRef: ref }}>
|
||||
<TopBar ref={ref} />
|
||||
<TopBarContext.Provider value={{ left, right }}>
|
||||
<TopBar leftRef={left} rightRef={right} />
|
||||
<Outlet />
|
||||
</TopBarContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export function useTopBarContext() {
|
||||
const ctx = useContext(TopBarContext);
|
||||
|
||||
if (!ctx) throw new Error('TopBarContext not found!');
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
36
interface/app/$libraryId/TopBar/NavigationButtons.tsx
Normal file
36
interface/app/$libraryId/TopBar/NavigationButtons.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Tooltip } from '@sd/ui';
|
||||
import { ArrowLeft, ArrowRight } from 'phosphor-react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { useSearchStore } from '~/hooks';
|
||||
import TopBarButton from './TopBarButton';
|
||||
|
||||
export const NavigationButtons = () => {
|
||||
const navigate = useNavigate();
|
||||
const { isFocused } = useSearchStore();
|
||||
const idx = history.state.idx as number;
|
||||
|
||||
return (
|
||||
<div data-tauri-drag-region className="flex">
|
||||
<Tooltip label="Navigate back">
|
||||
<TopBarButton
|
||||
rounding='left'
|
||||
// className="text-[14px] text-ink-dull"
|
||||
onClick={() => navigate(-1)}
|
||||
disabled={isFocused || idx === 0}
|
||||
>
|
||||
<ArrowLeft size={14} className='m-[4px]' weight="bold" />
|
||||
</TopBarButton>
|
||||
</Tooltip>
|
||||
<Tooltip label="Navigate forward">
|
||||
<TopBarButton
|
||||
rounding='right'
|
||||
// className="text-[14px] text-ink-dull"
|
||||
onClick={() => navigate(1)}
|
||||
disabled={isFocused || idx === history.length - 1}
|
||||
>
|
||||
<ArrowRight size={14} className='m-[4px]' weight="bold" />
|
||||
</TopBarButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
18
interface/app/$libraryId/TopBar/Portal.tsx
Normal file
18
interface/app/$libraryId/TopBar/Portal.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useTopBarContext } from './Layout';
|
||||
|
||||
interface Props {
|
||||
left?: ReactNode;
|
||||
right?: ReactNode;
|
||||
}
|
||||
export const TopBarPortal = ({ left, right }: Props) => {
|
||||
const ctx = useTopBarContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
{left && ctx.left.current && createPortal(left, ctx.left.current)}
|
||||
{right && ctx.right.current && createPortal(right, ctx.right.current)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DotsThreeCircle } from 'phosphor-react';
|
||||
import React, { HTMLAttributes, forwardRef } from 'react';
|
||||
import { Popover } from '@sd/ui';
|
||||
import { TOP_BAR_ICON_STYLE, ToolOption } from '.';
|
||||
import TopBarButton, { TopBarButtonProps } from './TopBarButton';
|
||||
import { TOP_BAR_ICON_STYLE, ToolOption } from './TopBarOptions';
|
||||
|
||||
const GroupTool = forwardRef<
|
||||
HTMLButtonElement,
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
import clsx from 'clsx';
|
||||
import { useContext, useLayoutEffect, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useLayoutEffect, useState } from 'react';
|
||||
import { Popover, Tooltip } from '@sd/ui';
|
||||
import { ToolOption } from '.';
|
||||
import { TopBarContext } from './Layout';
|
||||
import TopBarButton from './TopBarButton';
|
||||
import TopBarMobile from './TopBarMobile';
|
||||
|
||||
interface TopBarChildrenProps {
|
||||
toolOptions?: ToolOption[][];
|
||||
export interface ToolOption {
|
||||
icon: JSX.Element;
|
||||
onClick?: () => void;
|
||||
individual?: boolean;
|
||||
toolTipLabel: string;
|
||||
topBarActive?: boolean;
|
||||
popOverComponent?: JSX.Element;
|
||||
showAtResolution: ShowAtResolution;
|
||||
}
|
||||
|
||||
export default ({ toolOptions }: TopBarChildrenProps) => {
|
||||
const ctx = useContext(TopBarContext);
|
||||
const target = ctx.topBarChildrenRef?.current;
|
||||
export type ShowAtResolution = 'sm:flex' | 'md:flex' | 'lg:flex' | 'xl:flex' | '2xl:flex';
|
||||
interface TopBarChildrenProps {
|
||||
options?: ToolOption[][];
|
||||
}
|
||||
|
||||
export const TOP_BAR_ICON_STYLE = 'm-0.5 w-[18px] h-[18px] text-ink-dull';
|
||||
|
||||
export default ({ options }: TopBarChildrenProps) => {
|
||||
const [windowSize, setWindowSize] = useState(0);
|
||||
const toolsNotSmFlex = toolOptions
|
||||
const toolsNotSmFlex = options
|
||||
?.flatMap((group) => group)
|
||||
.filter((t) => t.showAtResolution !== 'sm:flex');
|
||||
|
||||
@@ -28,14 +36,10 @@ export default ({ toolOptions }: TopBarChildrenProps) => {
|
||||
return () => window.removeEventListener('resize', handleResize);
|
||||
}, []);
|
||||
|
||||
if (!target) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createPortal(
|
||||
return (
|
||||
<div data-tauri-drag-region className="flex w-full flex-row justify-end">
|
||||
<div data-tauri-drag-region className={`flex gap-0`}>
|
||||
{toolOptions?.map((group, groupIndex) => {
|
||||
{options?.map((group, groupIndex) => {
|
||||
return group.map(
|
||||
(
|
||||
{
|
||||
@@ -49,14 +53,14 @@ export default ({ toolOptions }: TopBarChildrenProps) => {
|
||||
},
|
||||
index
|
||||
) => {
|
||||
const groupCount = toolOptions.length;
|
||||
const groupCount = options.length;
|
||||
const roundingCondition = individual
|
||||
? 'both'
|
||||
: index === 0
|
||||
? 'left'
|
||||
: index === group.length - 1
|
||||
? 'right'
|
||||
: 'none';
|
||||
? 'left'
|
||||
: index === group.length - 1
|
||||
? 'right'
|
||||
: 'none';
|
||||
return (
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
@@ -109,12 +113,11 @@ export default ({ toolOptions }: TopBarChildrenProps) => {
|
||||
})}
|
||||
</div>
|
||||
<TopBarMobile
|
||||
toolOptions={toolOptions}
|
||||
className={`${
|
||||
toolOptions={options}
|
||||
className={
|
||||
windowSize <= 1279 && (toolsNotSmFlex?.length as number) > 0 ? 'flex' : 'hidden'
|
||||
}`}
|
||||
}
|
||||
/>
|
||||
</div>,
|
||||
target
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,37 +1,33 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { RefObject } from 'react';
|
||||
import { NavigationButtons } from './NavigationButtons';
|
||||
import SearchBar from './SearchBar';
|
||||
|
||||
export interface ToolOption {
|
||||
icon: JSX.Element;
|
||||
onClick?: () => void;
|
||||
individual?: boolean;
|
||||
toolTipLabel: string;
|
||||
topBarActive?: boolean;
|
||||
popOverComponent?: JSX.Element;
|
||||
showAtResolution: ShowAtResolution;
|
||||
}
|
||||
|
||||
export type ShowAtResolution = 'sm:flex' | 'md:flex' | 'lg:flex' | 'xl:flex' | '2xl:flex';
|
||||
|
||||
export const TOP_BAR_ICON_STYLE = 'm-0.5 w-5 h-5 text-ink-dull';
|
||||
export const TOP_BAR_HEIGHT = 46;
|
||||
|
||||
const TopBar = forwardRef<HTMLDivElement>((_, ref) => {
|
||||
interface Props {
|
||||
leftRef?: RefObject<HTMLDivElement>;
|
||||
rightRef?: RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const TopBar = (props: Props) => {
|
||||
return (
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className="
|
||||
duration-250 top-bar-blur absolute left-0 top-0 z-50 flex
|
||||
h-[46px] w-full flex-row items-center justify-center overflow-hidden
|
||||
border-b border-sidebar-divider bg-app/90 px-5
|
||||
border-b border-sidebar-divider bg-app/90 px-3.5
|
||||
transition-[background-color,border-color] ease-out
|
||||
"
|
||||
>
|
||||
<div className="flex-1" />
|
||||
<div data-tauri-drag-region className="flex flex-1 flex-row items-center">
|
||||
<NavigationButtons />
|
||||
<div ref={props.leftRef} />
|
||||
</div>
|
||||
<SearchBar />
|
||||
<div className="flex-1" ref={ref} />
|
||||
<div className="flex-1" ref={props.rightRef} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default TopBar;
|
||||
|
||||
Reference in New Issue
Block a user