Skip to content

Commit

Permalink
Minor improvements to recipes page
Browse files Browse the repository at this point in the history
  • Loading branch information
spaaaacccee committed Nov 30, 2023
1 parent 0ec934d commit 143fbc5
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 62 deletions.
19 changes: 14 additions & 5 deletions client/src/components/generic/Snackbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ import {
useState,
} from "react";

const SnackbarContext = createContext<
(message?: string, secondary?: string) => () => void
>(() => noop);
type A = (
message?: string,
secondary?: string,
options?: {
error?: boolean;
}
) => () => void;

const SnackbarContext = createContext<A>(() => noop);

export interface SnackbarMessage {
message?: ReactNode;
Expand Down Expand Up @@ -51,7 +57,7 @@ export function SnackbarProvider({ children }: { children?: ReactNode }) {
}, [snackPack, current, open]);

const handleMessage = useCallback(
(message?: string, secondary?: string) => {
((message?: string, secondary?: string, options = {}) => {
setSnackPack((prev) => [
...prev,
{
Expand All @@ -63,8 +69,11 @@ export function SnackbarProvider({ children }: { children?: ReactNode }) {
content: filter([message, secondary]).join(", "),
timestamp: `${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`,
}));
if (options.error) {
console.error(`${message}, ${secondary}`);
}
return () => handleClose("");
},
}) as A,
[setSnackPack]
);

Expand Down
97 changes: 48 additions & 49 deletions client/src/pages/RecipesPage.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { WorkspacesOutlined } from "@mui/icons-material";
import {
Box,
CircularProgress,
List,
ListItemButton,
ListItemIcon,
ListItemText,
Typography as Type,
} from "@mui/material";
import { Flex } from "components/generic/Flex";
import { Scroll } from "components/generic/Scrollbars";
import { useSnackbar } from "components/generic/Snackbar";
import { useViewTreeContext } from "components/inspector/ViewTree";
import { useWorkspace } from "hooks/useWorkspace";
import { map, startCase, values } from "lodash";
import { chain as _, entries, map } from "lodash";
import { Page } from "pages/Page";
import { ReactNode } from "react";
import { useAsync } from "react-async-hook";
import { useLoadingState } from "slices/loading";

function stripExtension(path: string) {
return path.split(".")[0];
Expand All @@ -25,68 +26,60 @@ function basename(path: string) {
}

export function RecipesPage() {
const notify = useSnackbar();
const { controls, onChange, state } = useViewTreeContext();
const { load } = useWorkspace();
const usingLoadingState = useLoadingState();

const { result: files } = useAsync(async () => {
const { result: files, loading } = useAsync(async () => {
const paths = import.meta.glob("/public/recipes/*.workspace", {
as: "url",
});
return await Promise.all(values(paths).map((f) => f()));
return await Promise.all(
entries(paths).map((entry) => getFileInfo(...entry))
);
}, []);

async function open(path: string) {
try {
const response = await fetch(path);

if (!response.ok) {
throw new Error("Network response was not ok");
const open = (path: string) =>
usingLoadingState(async () => {
try {
notify(`Loading ${basename(path)}...`);
const response = await fetch(path);
if (!response.ok) {
notify(`Couldn't load ${basename(path)}`, `Network error`, {
error: true,
});
}
const blob = await response.blob();
const file = new File([blob], basename(path), { type: blob.type });
// It is correct to not wait for this promise
load(file);
} catch (e) {
notify(`Couldn't load ${basename(path)}`, `${e}`, {
error: true,
});
}

const blob = await response.blob();
const filename = basename(path);
const file = new File([blob], filename, { type: blob.type });

load(file);
} catch (error) {
console.error("There was a problem with the fetch operation:", error);
}
}

function renderSection(label: ReactNode, content: ReactNode) {
return (
<Box sx={{ pt: 2 }}>
<Type variant="overline" color="text.secondary">
{label}
</Type>
<Type variant="body2">{content}</Type>
</Box>
);
}
});

return (
<Page onChange={onChange} stack={state}>
<Page.Content>
<Flex vertical>
<Scroll y>
<Box sx={{ pt: 6 }}>
{renderSection(
<Box sx={{ px: 2 }}>Recipes</Box>,
<>
<List>
{map(files, (path, i) => (
<ListItemButton key={i} onClick={() => open(path)}>
<ListItemIcon>
<WorkspacesOutlined />
</ListItemIcon>
<ListItemText
primary={startCase(stripExtension(basename(path)))}
secondary={basename(path)}
/>
</ListItemButton>
))}
</List>
</>
{!loading ? (
<List>
{map(files, ({ name, path }, i) => (
<ListItemButton key={i} onClick={() => open(path)}>
<ListItemIcon>
<WorkspacesOutlined />
</ListItemIcon>
<ListItemText primary={name} secondary={basename(path)} />
</ListItemButton>
))}
</List>
) : (
<CircularProgress sx={{ m: 2 }} />
)}
</Box>
</Scroll>
Expand All @@ -96,3 +89,9 @@ export function RecipesPage() {
</Page>
);
}
async function getFileInfo(k: string, f: () => Promise<string>) {
return {
name: _(k).thru(basename).thru(stripExtension).startCase().value(),
path: await f(),
};
}
13 changes: 6 additions & 7 deletions client/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { TreePage } from "./TreePage";
import { ViewportPage } from "./ViewportPage";
import { RecipesPage } from "./RecipesPage";


export type PageMeta = {
id: string;
name: string;
Expand All @@ -30,6 +29,12 @@ export type PageMeta = {
};

export const pages: Dictionary<PageMeta> = {
recipes: {
id: "recipes",
name: "Recipes",
icon: <WorkspacesOutlined />,
content: RecipesPage,
},
viewport: {
id: "viewport",
name: "Viewport",
Expand Down Expand Up @@ -78,10 +83,4 @@ export const pages: Dictionary<PageMeta> = {
icon: <InfoOutlined />,
content: AboutPage,
},
recipes: {
id: "recipes",
name: "Recipes",
icon: <WorkspacesOutlined />,
content: RecipesPage,
},
};
4 changes: 3 additions & 1 deletion client/src/slices/loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type Loading = {
map: number;
connections: number;
features: number;
general: number;
};

type A = { action: "start" | "end"; key: keyof Loading };
Expand All @@ -18,6 +19,7 @@ export const [useLoading, LoadingProvider] = createSlice<Loading, A>(
connections: 0,
features: 0,
map: 0,
general: 0,
},
{
reduce: (prev, { action, key }: A) => {
Expand All @@ -40,7 +42,7 @@ export function useAnyLoading() {
return some(values(loading));
}

export function useLoadingState(key: keyof Loading) {
export function useLoadingState(key: keyof Loading = "general") {
const [, dispatch] = useLoading();

return useCallback(
Expand Down

0 comments on commit 143fbc5

Please sign in to comment.