Better loading/empty visuals

This commit is contained in:
Dustin Brett 2025-05-17 14:01:31 -07:00
parent 8708b3a230
commit e992b6b0ec
13 changed files with 161 additions and 129 deletions

View File

@ -1,5 +1,5 @@
import styled from "styled-components";
import StyledLoading from "components/system/Files/FileManager/StyledLoading";
import StyledLoading from "components/system/Apps/StyledLoading";
import StyledDetailsFileManager from "components/system/Files/Views/Details/StyledFileManager";
import StyledIconFileManager from "components/system/Files/Views/Icon/StyledFileManager";
@ -21,6 +21,7 @@ const StyledFileExplorer = styled.div`
${StyledLoading} {
height: ${({ theme }) =>
`calc(100% - ${theme.sizes.fileExplorer.navBarHeight} - ${theme.sizes.fileExplorer.statusBarHeight})`};
position: absolute;
}
`;

View File

@ -1,7 +1,7 @@
import { useEffect, useRef, useState } from "react";
import { getNetworkConfig } from "components/apps/IRC/config";
import { type ComponentProcessProps } from "components/system/Apps/RenderComponent";
import StyledLoading from "components/system/Files/FileManager/StyledLoading";
import StyledLoading from "components/system/Apps/StyledLoading";
import { useProcesses } from "contexts/process";
import processDirectory from "contexts/process/directory";
import { IFRAME_CONFIG } from "utils/constants";

View File

@ -2,7 +2,7 @@ import { basename, dirname, join } from "path";
import { useCallback, useEffect, useRef, useState } from "react";
import StyledPaint from "components/apps/Paint/StyledPaint";
import { type ComponentProcessProps } from "components/system/Apps/RenderComponent";
import StyledLoading from "components/system/Files/FileManager/StyledLoading";
import StyledLoading from "components/system/Apps/StyledLoading";
import useFileDrop from "components/system/Files/FileManager/useFileDrop";
import useTitle from "components/system/Window/useTitle";
import { useFileSystem } from "contexts/fileSystem";

View File

@ -1,7 +1,7 @@
import { memo, useMemo, useRef, useState } from "react";
import styled, { type IStyledComponent } from "styled-components";
import { type FastOmit } from "styled-components/dist/types";
import StyledLoading from "components/system/Files/FileManager/StyledLoading";
import StyledLoading from "components/system/Apps/StyledLoading";
import useFileDrop from "components/system/Files/FileManager/useFileDrop";
import { useProcesses } from "contexts/process";

View File

@ -0,0 +1,29 @@
import styled from "styled-components";
type StyledLoadingProps = {
$hasColumns?: boolean;
};
const StyledLoading = styled.div<StyledLoadingProps>`
cursor: wait;
height: 100%;
width: 100%;
&::before {
color: #fff;
content: "Working on it...";
display: flex;
font-size: 12px;
font-weight: 200;
justify-content: center;
letter-spacing: 0.3px;
mix-blend-mode: difference;
padding-top: ${({ $hasColumns, theme }) =>
$hasColumns
? theme.sizes.window.textTopPadding +
theme.sizes.fileManager.columnHeight
: theme.sizes.window.textTopPadding}px;
}
`;
export default StyledLoading;

View File

@ -12,7 +12,7 @@ const StyledColumns = styled.span`
ol {
display: flex;
height: ${({ theme }) => theme.sizes.fileManager.columnHeight};
height: ${({ theme }) => theme.sizes.fileManager.columnHeight}px;
li {
color: rgb(222 222 222);
@ -46,7 +46,7 @@ const StyledColumns = styled.span`
.resize {
border-left: 1px solid rgb(99 99 99);
cursor: col-resize;
height: 25px;
height: ${({ theme }) => theme.sizes.fileManager.columnHeight}px;
padding-left: ${({ theme }) =>
theme.sizes.fileManager.columnResizeWidth}px;
position: absolute;

View File

@ -1,4 +1,4 @@
import { memo, useRef } from "react";
import { memo, useCallback, useRef } from "react";
import { useTheme } from "styled-components";
import dynamic from "next/dynamic";
import { sortFiles } from "components/system/Files/FileManager/functions";
@ -35,23 +35,18 @@ const Columns: FC<ColumnsProps> = ({
const lastClientX = useRef(0);
const { setSortOrder, sortOrders } = useSession();
const [, sortedBy = "name", ascending] = sortOrders[directory] ?? [];
return (
<StyledColumns>
<ol>
{DEFAULT_COLUMN_ORDER.map((name) => (
<li
key={columns[name].name}
onPointerDownCapture={(event) => {
const onPointerDownCapture = useCallback(
(name: string) => (event: React.PointerEvent<HTMLLIElement>) => {
if (event.button !== 0) return;
draggingRef.current =
(event.target as HTMLElement).className === "resize"
? name
: "";
(event.target as HTMLElement).className === "resize" ? name : "";
lastClientX.current = event.clientX;
}}
onPointerMoveCapture={(event) => {
},
[]
);
const onPointerMoveCapture = useCallback(
(event: React.PointerEvent<HTMLLIElement>) => {
if (draggingRef.current) {
const dragName = draggingRef.current as ColumnName;
@ -60,14 +55,11 @@ const Columns: FC<ColumnsProps> = ({
const newColumns = { ...currentColumns };
const newSize =
newColumns[dragName].width +
event.clientX -
lastClientX.current;
newColumns[dragName].width + event.clientX - lastClientX.current;
if (
newSize < sizes.fileManager.columnMinWidth ||
Math.abs(lastClientX.current - event.clientX) >
MAX_STEPS_PER_RESIZE
Math.abs(lastClientX.current - event.clientX) > MAX_STEPS_PER_RESIZE
) {
return newColumns;
}
@ -78,8 +70,11 @@ const Columns: FC<ColumnsProps> = ({
return newColumns;
});
}
}}
onPointerUpCapture={(event) => {
},
[setColumns, sizes.fileManager.columnMinWidth]
);
const onPointerUpCapture = useCallback(
(name: string) => (event: React.PointerEvent<HTMLLIElement>) => {
if (event.button !== 0) return;
if (draggingRef.current) {
@ -95,7 +90,19 @@ const Columns: FC<ColumnsProps> = ({
!ascending
);
}
}}
},
[ascending, directory, files, setSortOrder]
);
return (
<StyledColumns>
<ol>
{DEFAULT_COLUMN_ORDER.map((name) => (
<li
key={columns[name].name}
onPointerDownCapture={onPointerDownCapture(name)}
onPointerMoveCapture={onPointerMoveCapture}
onPointerUpCapture={onPointerUpCapture(name)}
style={{ width: `${columns[name].width}px` }}
>
{sortedBy === name && <Down flip={ascending} />}

View File

@ -1,6 +1,10 @@
import styled from "styled-components";
const StyledEmpty = styled.div`
type StyledEmptyProps = {
$hasColumns?: boolean;
};
const StyledEmpty = styled.div<StyledEmptyProps>`
position: absolute;
width: 100%;
@ -13,7 +17,11 @@ const StyledEmpty = styled.div`
justify-content: center;
letter-spacing: 0.3px;
mix-blend-mode: difference;
padding-top: 14px;
padding-top: ${({ $hasColumns, theme }) =>
$hasColumns
? theme.sizes.window.textTopPadding +
theme.sizes.fileManager.columnHeight
: theme.sizes.window.textTopPadding}px;
}
`;

View File

@ -1,19 +0,0 @@
import styled from "styled-components";
const StyledLoading = styled.div`
cursor: wait;
height: 100%;
width: 100%;
&::before {
color: #fff;
content: "Working on it...";
display: flex;
font-size: 12px;
justify-content: center;
mix-blend-mode: difference;
padding-top: 18px;
}
`;
export default StyledLoading;

View File

@ -1,7 +1,7 @@
import { basename, join } from "path";
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
import dynamic from "next/dynamic";
import StyledLoading from "components/system/Files/FileManager/StyledLoading";
import StyledLoading from "components/system/Apps/StyledLoading";
import StatusBar from "components/system/Files/FileManager/StatusBar";
import {
DEFAULT_COLUMNS,
@ -85,11 +85,12 @@ const FileManager: FC<FileManagerProps> = ({
const [renaming, setRenaming] = useState("");
const [mounted, setMounted] = useState<boolean>(false);
const fileManagerRef = useRef<HTMLOListElement | null>(null);
const { focusedEntries, focusableEntry, ...focusFunctions } =
useFocusableEntries(
fileManagerRef,
!isStartMenu && !isDesktop && !isDetailsView
const isFileExplorerIconView = useMemo(
() => !isStartMenu && !isDesktop && !isDetailsView,
[isDesktop, isDetailsView, isStartMenu]
);
const { focusedEntries, focusableEntry, ...focusFunctions } =
useFocusableEntries(fileManagerRef, isFileExplorerIconView);
const { fileActions, files, folderActions, isLoading, updateFiles } =
useFolder(url, setRenaming, focusFunctions, {
hideFolders,
@ -121,7 +122,11 @@ const FileManager: FC<FileManagerProps> = ({
isDesktop,
isStartMenu
);
const loading = (!hideLoading && isLoading) || url !== currentUrl;
const loading = useMemo(() => {
if (hideLoading) return false;
return isLoading || url !== currentUrl;
}, [currentUrl, hideLoading, isLoading, url]);
const setView = useCallback(
(newView: FileManagerViewNames) => {
setViews((currentViews) => ({ ...currentViews, [url]: newView }));
@ -151,12 +156,10 @@ const FileManager: FC<FileManagerProps> = ({
[keyShortcuts, renaming]
);
const fileKeys = useMemo(() => Object.keys(files), [files]);
const isEmptyFolder =
!isDesktop &&
!isStartMenu &&
!loading &&
view !== "list" &&
fileKeys.length === 0;
const isEmptyFolder = useMemo(
() => !isDesktop && !isStartMenu && !loading && fileKeys.length === 0,
[fileKeys.length, isDesktop, isStartMenu, loading]
);
useEffect(() => {
if (
@ -231,17 +234,14 @@ const FileManager: FC<FileManagerProps> = ({
return (
<>
{loading ? (
<StyledLoading />
) : (
<>
{isEmptyFolder && <StyledEmpty />}
{loading && <StyledLoading $hasColumns={isDetailsView} />}
{!loading && isEmptyFolder && <StyledEmpty $hasColumns={isDetailsView} />}
<StyledFileManager
ref={fileManagerRef}
$isEmptyFolder={isEmptyFolder}
$scrollable={!hideScrolling}
onKeyDownCapture={onKeyDown}
{...(readOnly
onKeyDownCapture={loading ? undefined : onKeyDown}
{...(loading || readOnly
? { onContextMenu: haltEvent }
: {
$selecting: isSelecting,
@ -259,6 +259,8 @@ const FileManager: FC<FileManagerProps> = ({
setColumns={setColumns}
/>
)}
{!loading && (
<>
{isSelecting && <StyledSelection style={selectionStyling} />}
{fileKeys.map((file) => (
<StyledFileEntry
@ -294,9 +296,9 @@ const FileManager: FC<FileManagerProps> = ({
/>
</StyledFileEntry>
))}
</StyledFileManager>
</>
)}
</StyledFileManager>
{showStatusBar && (
<StatusBar
count={loading ? 0 : fileKeys.length}

View File

@ -168,8 +168,10 @@ const useFolder = (
},
[directory, readFile]
);
const isSimpleSort =
skipSorting || !sortBy || sortBy === "name" || sortBy === "type";
const isSimpleSort = useMemo(
() => skipSorting || !sortBy || sortBy === "name" || sortBy === "type",
[skipSorting, sortBy]
);
const updateFiles = useCallback(
async (newFile?: string, oldFile?: string) => {
if (oldFile) {
@ -739,6 +741,7 @@ const useFolder = (
useEffect(() => {
if (directory !== currentDirectory) {
setIsLoading(true);
setCurrentDirectory(directory);
setFiles(NO_FILES);
}

View File

@ -1,6 +1,6 @@
import { m as motion } from "motion/react";
import styled from "styled-components";
import StyledLoading from "components/system/Files/FileManager/StyledLoading";
import StyledLoading from "components/system/Apps/StyledLoading";
type StyledWindowProps = {
$backgroundBlur?: string;

View File

@ -26,7 +26,7 @@ const sizes = {
},
fileManager: {
columnGap: "1px",
columnHeight: "25px",
columnHeight: 25,
columnMinWidth: 70,
columnResizeWidth: 7,
detailsEndPadding: 16,
@ -87,6 +87,7 @@ const sizes = {
window: {
cascadeOffset: 26,
outline: "1px",
textTopPadding: 14,
},
};