mirror of
https://github.com/nix-community/noogle.git
synced 2024-11-24 19:06:00 +03:00
INIT: first prototype of frontend
This commit is contained in:
commit
c51722be2d
3
.eslintrc.json
Normal file
3
.eslintrc.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
44
.gitignore
vendored
Normal file
44
.gitignore
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# nix
|
||||
.direnv/
|
||||
result
|
||||
result-*
|
||||
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
result
|
||||
result-*
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Static page with nextjs example
|
||||
|
||||
- Generates a static page
|
||||
- Includes custom Image loader for static page generation
|
||||
|
||||
## Build
|
||||
|
||||
> ### ! The build step is completly independent of develop step and can be run right after checkout
|
||||
|
||||
`nix build .#`
|
||||
|
||||
This should create to following result:
|
||||
|
||||
- static/
|
||||
- __index.html__
|
||||
- favicon.ico
|
||||
- 404.html
|
||||
- vercel-svg
|
||||
- _next/
|
||||
- static/...
|
||||
- ...
|
||||
|
||||
## Develop
|
||||
|
||||
`nix develop`
|
||||
|
||||
This command creates the node_modules folder with all needed dependencies
|
103
components/basicList/basicList.spec.tsx
Normal file
103
components/basicList/basicList.spec.tsx
Normal file
@ -0,0 +1,103 @@
|
||||
import "@testing-library/jest-dom";
|
||||
// TODO: important mock zustand!
|
||||
// State from previous tests leaking into other test cases because zustand is never reset in its own
|
||||
|
||||
import * as React from "react";
|
||||
import { render, screen, act } from "@testing-library/react";
|
||||
import mockAxios from "jest-mock-axios";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import { ImageList } from "./";
|
||||
import { QueryClient, QueryClientProvider } from "react-query";
|
||||
import { SnackbarProvider } from "notistack";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
const Wrapper = (element: React.ReactNode) => (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<SnackbarProvider>{element}</SnackbarProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
|
||||
const getImagesResp = [
|
||||
{
|
||||
filename: "testfile.iso",
|
||||
hash: "3993d64556f3ae803986f6d1c2debaa8f5a2a77da70cc35f86af6f99c849fe80",
|
||||
modify_time: "2022-07-28T07:45:32.331998395Z",
|
||||
size_bytes: 513,
|
||||
},
|
||||
{
|
||||
filename: "full.img",
|
||||
hash: "85c6a11c928611caff965aa2fc267b51ad3fc06657d0ee67ae00fec1711e81ef",
|
||||
modify_time: "2022-07-29T07:33:20.075281078Z",
|
||||
size_bytes: 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
filename: "small.img",
|
||||
hash: "e8edbf1bb6121a38e8ee3a60e34a31887955bc9a292e9ef3bd598e8ccb7fef5a",
|
||||
modify_time: "2022-07-29T07:34:10.442184606Z",
|
||||
size_bytes: 1,
|
||||
},
|
||||
];
|
||||
|
||||
describe("render imageList", () => {
|
||||
afterEach(() => {
|
||||
mockAxios.reset();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await act(async () => {
|
||||
mockAxios.get.mockResolvedValue({ data: getImagesResp });
|
||||
render(Wrapper(<ImageList />), {});
|
||||
});
|
||||
});
|
||||
|
||||
test("list is shown & has proper length", async () => {
|
||||
const list = await screen.getByRole("list", { name: "image-list" });
|
||||
const listItems = await screen.getAllByRole("listitem", {
|
||||
name: "image-entry-item",
|
||||
});
|
||||
expect(list).toBeVisible();
|
||||
expect(listItems).toHaveLength(getImagesResp.length);
|
||||
expect(mockAxios.get).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test("search: a term", async () => {
|
||||
const searchInput = await screen.getByRole("textbox", {
|
||||
name: "search-input",
|
||||
});
|
||||
const searchButton = await screen.getByRole("button", {
|
||||
name: "search-button",
|
||||
});
|
||||
await userEvent.type(searchInput, ".img");
|
||||
await userEvent.click(searchButton);
|
||||
|
||||
/*
|
||||
search for filename with ".img" in it
|
||||
-> should yield:
|
||||
[ "full.img", "small.img" ]
|
||||
*/
|
||||
const listItems = await screen.getAllByRole("listitem", {
|
||||
name: "image-entry-item",
|
||||
});
|
||||
expect(listItems).toHaveLength(2);
|
||||
expect(listItems[0]).toHaveTextContent("full.img");
|
||||
expect(listItems[1]).toHaveTextContent("small.img");
|
||||
});
|
||||
|
||||
test("delete an image", async () => {
|
||||
const deleteButtons = await screen.getAllByRole("button", {
|
||||
name: "delete-image",
|
||||
});
|
||||
|
||||
const firstDeleteButton = deleteButtons?.[0];
|
||||
|
||||
expect(firstDeleteButton).toBeEnabled();
|
||||
|
||||
await userEvent.click(firstDeleteButton);
|
||||
|
||||
//TODO: dont have delete functionality yet
|
||||
// expect(mockedDeleteFn).toBeCalled();
|
||||
});
|
||||
});
|
175
components/basicList/basicList.tsx
Normal file
175
components/basicList/basicList.tsx
Normal file
@ -0,0 +1,175 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Box,
|
||||
IconButton,
|
||||
List,
|
||||
ListItem,
|
||||
Pagination,
|
||||
Stack,
|
||||
Typography,
|
||||
Grid,
|
||||
} from "@mui/material";
|
||||
import { BasicDataViewProps, NixType } from "../../types/basicDataView";
|
||||
import { SearchInput } from "../searchInput";
|
||||
import Radio from "@mui/material/Radio";
|
||||
import RadioGroup from "@mui/material/RadioGroup";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import FormControl from "@mui/material/FormControl";
|
||||
import FormLabel from "@mui/material/FormLabel";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||
|
||||
export type BasicListItem = {
|
||||
item: React.ReactNode;
|
||||
key: string;
|
||||
};
|
||||
export type BasicListProps = BasicDataViewProps & {
|
||||
handleFilter: (t: NixType, mode: "from" | "to") => void;
|
||||
preview: React.ReactNode;
|
||||
};
|
||||
|
||||
interface SelectOptionProps {
|
||||
label: string;
|
||||
handleChange: (value: string) => void;
|
||||
options: {
|
||||
value: string;
|
||||
label: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
const SelectOption = (props: SelectOptionProps) => {
|
||||
const { label, handleChange, options } = props;
|
||||
const [value, setValue] = React.useState<NixType>("any");
|
||||
|
||||
const _handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newVal = (event.target as HTMLInputElement).value as NixType;
|
||||
setValue(newVal);
|
||||
handleChange(newVal);
|
||||
};
|
||||
const handleClear = () => {
|
||||
setValue("any");
|
||||
handleChange("any");
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<FormLabel>
|
||||
<Box>
|
||||
<IconButton
|
||||
// disabled={value === ""}
|
||||
aria-label="clear-button"
|
||||
onClick={handleClear}
|
||||
>
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
{label}
|
||||
</Box>
|
||||
</FormLabel>
|
||||
|
||||
<RadioGroup sx={{ pl: 1.5 }} value={value} onChange={_handleChange}>
|
||||
{options.map(({ value, label }) => (
|
||||
<FormControlLabel
|
||||
key={value}
|
||||
value={value}
|
||||
control={<Radio />}
|
||||
label={label}
|
||||
/>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export function BasicList(props: BasicListProps) {
|
||||
const { items, pageCount = 1, handleSearch, handleFilter, preview } = props;
|
||||
// const [from, setFrom] = useState<NixType>("any");
|
||||
// const [to, setTo] = useState<NixType>("any");
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
|
||||
const handlePageChange = (
|
||||
_event: React.ChangeEvent<unknown>,
|
||||
value: number
|
||||
) => {
|
||||
setPage(value);
|
||||
};
|
||||
|
||||
const _handleFilter = (t: NixType, mode: "from" | "to") => {
|
||||
handleFilter(t, mode);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const _handleSearch = (term: string) => {
|
||||
handleSearch && handleSearch(term);
|
||||
setSearchTerm(term);
|
||||
setPage(1);
|
||||
};
|
||||
const nixTypes: NixType[] = [
|
||||
"any",
|
||||
"attrset",
|
||||
"list",
|
||||
"string",
|
||||
"bool",
|
||||
"int",
|
||||
];
|
||||
return (
|
||||
<Stack>
|
||||
<SearchInput
|
||||
placeholder="search nix functions"
|
||||
handleSearch={_handleSearch}
|
||||
clearSearch={() => _handleSearch("")}
|
||||
/>
|
||||
<Box>
|
||||
<Grid container>
|
||||
<Grid item xs={3}>
|
||||
<Stack direction="row">
|
||||
<SelectOption
|
||||
label="from type"
|
||||
handleChange={(value) => {
|
||||
_handleFilter(value as NixType, "from");
|
||||
}}
|
||||
options={nixTypes.map((v) => ({ value: v, label: v }))}
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<ChevronRightIcon />
|
||||
</Typography>
|
||||
<SelectOption
|
||||
label="to type"
|
||||
handleChange={(value) => {
|
||||
_handleFilter(value as NixType, "to");
|
||||
}}
|
||||
options={nixTypes.map((v) => ({ value: v, label: v }))}
|
||||
/>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
{preview}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
<List aria-label="basic-list" sx={{ pt: 0 }}>
|
||||
{items.map(({ item, key }) => (
|
||||
<ListItem key={key} aria-label={`item-${key}`} sx={{ px: 0 }}>
|
||||
{item}
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
|
||||
<Pagination
|
||||
sx={{ display: "flex", justifyContent: "center", mt: 1, mb: 10 }}
|
||||
count={pageCount}
|
||||
color="primary"
|
||||
page={page}
|
||||
onChange={handlePageChange}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
2
components/basicList/index.tsx
Normal file
2
components/basicList/index.tsx
Normal file
@ -0,0 +1,2 @@
|
||||
export { BasicList } from "./basicList";
|
||||
export type { BasicListProps, BasicListItem } from "./basicList";
|
40
components/functionItem/functionItem.tsx
Normal file
40
components/functionItem/functionItem.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
ListItemText,
|
||||
Paper,
|
||||
Stack,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
|
||||
interface FunctionItemProps {
|
||||
selected: boolean;
|
||||
name: String;
|
||||
info: {
|
||||
"attr-path": String;
|
||||
source: String;
|
||||
from: String;
|
||||
to: String;
|
||||
};
|
||||
}
|
||||
export default function FunctionItem(props: FunctionItemProps) {
|
||||
const { name, info, selected } = props;
|
||||
return (
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "left",
|
||||
color: selected ? "primary.main" : undefined,
|
||||
borderColor: selected ? "action.selected" : "none",
|
||||
borderWidth: 1,
|
||||
borderStyle: selected ? "solid" : "none",
|
||||
}}
|
||||
>
|
||||
<Stack>
|
||||
<ListItemText primary={name} secondary={info["attr-path"]} />
|
||||
<Typography>{`${info.from} -> ${info.to} `}</Typography>
|
||||
</Stack>
|
||||
</Paper>
|
||||
);
|
||||
}
|
10
components/image/image.tsx
Normal file
10
components/image/image.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import NextImage, { ImageLoaderProps, ImageProps } from "next/image";
|
||||
|
||||
// opt-out of image optimization, no-op
|
||||
const customLoader = ({ src }: ImageLoaderProps) => {
|
||||
return src;
|
||||
};
|
||||
|
||||
export function Image(props: ImageProps) {
|
||||
return <NextImage {...props} loader={customLoader} />;
|
||||
}
|
1
components/image/index.tsx
Normal file
1
components/image/index.tsx
Normal file
@ -0,0 +1 @@
|
||||
export { Image } from "./image";
|
1
components/layout/index.ts
Normal file
1
components/layout/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Layout } from "./layout"
|
42
components/layout/layout.tsx
Normal file
42
components/layout/layout.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import { Box, Typography, Container, Link } from "@mui/material";
|
||||
// import Link from "next/link";
|
||||
|
||||
export interface LayoutProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Layout(props: LayoutProps) {
|
||||
const { children } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<Box sx={{ p: 2, backgroundColor: "primary.main" }}>
|
||||
<Typography variant="h1" sx={{ textAlign: "center", color: "#fff" }}>
|
||||
{`noog\u03BBe`}
|
||||
</Typography>
|
||||
</Box>
|
||||
</header>
|
||||
<main>
|
||||
<Container sx={{ pt: 0 }} maxWidth="xl">
|
||||
{children}
|
||||
</Container>
|
||||
</main>
|
||||
<footer
|
||||
style={{
|
||||
position: "fixed",
|
||||
bottom: 0,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
Powered by{" "}
|
||||
<Link sx={{ ml: 1 }} href="https://oceansprint.org/">
|
||||
{" "}
|
||||
OceanSprint
|
||||
</Link>
|
||||
</footer>
|
||||
</>
|
||||
);
|
||||
}
|
55
components/preview/preview.tsx
Normal file
55
components/preview/preview.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import {
|
||||
Box,
|
||||
Link,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
ListItemSecondaryAction,
|
||||
ListItemText,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { info } from "console";
|
||||
import { FuncData } from "../../pages";
|
||||
import LocalLibraryIcon from "@mui/icons-material/LocalLibrary";
|
||||
import InputIcon from "@mui/icons-material/Input";
|
||||
import OutputIcon from "@mui/icons-material/Output";
|
||||
|
||||
interface PreviewProps {
|
||||
func: FuncData;
|
||||
}
|
||||
|
||||
export const Preview = (props: PreviewProps) => {
|
||||
const { func } = props;
|
||||
return (
|
||||
<Box sx={{ p: 1, width: "100%" }}>
|
||||
<Typography variant="h2">{func.name}</Typography>
|
||||
<List sx={{ width: "100%" }}>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<LocalLibraryIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={func.info["attr-path"]}
|
||||
secondary={func.info["doc-url"]}
|
||||
/>
|
||||
<ListItemSecondaryAction>
|
||||
<Link href={func.info["doc-url"]}>View Docs</Link>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<InputIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={func.info.from} secondary="argument type" />
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<OutputIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={func.info.to} secondary="return type" />
|
||||
</ListItem>
|
||||
<ListItem></ListItem>
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
};
|
1
components/searchInput/index.tsx
Normal file
1
components/searchInput/index.tsx
Normal file
@ -0,0 +1 @@
|
||||
export { SearchInput } from "./searchInput";
|
56
components/searchInput/searchInput.spec.tsx
Normal file
56
components/searchInput/searchInput.spec.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import * as React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { SearchInput } from "./";
|
||||
|
||||
describe("render search", () => {
|
||||
const mockedSearch = jest.fn();
|
||||
mockedSearch.mockImplementation((term: string) => {
|
||||
return term;
|
||||
});
|
||||
const mockedClear = jest.fn();
|
||||
mockedClear.mockImplementation(() => {
|
||||
return undefined;
|
||||
});
|
||||
beforeEach(() => {
|
||||
render(
|
||||
<SearchInput
|
||||
handleSearch={mockedSearch}
|
||||
clearSearch={mockedClear}
|
||||
placeholder={"Search"}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
test("renders all elements from the searchbar", async () => {
|
||||
const inputBar = screen.getByRole("textbox");
|
||||
const clearButton = screen.getByRole("button", { name: "clear-button" });
|
||||
const searchButton = screen.getByRole("button", { name: "search-button" });
|
||||
expect(inputBar).toBeVisible();
|
||||
expect(searchButton).toBeVisible();
|
||||
expect(clearButton).toBeVisible();
|
||||
const term = "search for term";
|
||||
await userEvent.type(inputBar, term);
|
||||
await userEvent.click(searchButton);
|
||||
expect(mockedSearch).toBeCalledWith(term);
|
||||
});
|
||||
|
||||
test("search for a term", async () => {
|
||||
const inputBar = screen.getByRole("textbox");
|
||||
const searchButton = screen.getByRole("button", { name: "search-button" });
|
||||
const term = "search for term";
|
||||
await userEvent.type(inputBar, term);
|
||||
await userEvent.click(searchButton);
|
||||
expect(mockedSearch).toBeCalledWith(term);
|
||||
});
|
||||
|
||||
test("clearing search", async () => {
|
||||
const inputBar = screen.getByRole("textbox");
|
||||
const clearButton = screen.getByRole("button", { name: "clear-button" });
|
||||
const term = "search for term";
|
||||
await userEvent.type(inputBar, term);
|
||||
await userEvent.click(clearButton);
|
||||
expect(mockedClear).toBeCalled();
|
||||
});
|
||||
});
|
84
components/searchInput/searchInput.tsx
Normal file
84
components/searchInput/searchInput.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import React, { useState, useMemo } from "react";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import InputBase from "@mui/material/InputBase";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
import { debounce } from "@mui/material";
|
||||
|
||||
export interface SearchInputProps {
|
||||
handleSearch: (term: string) => void;
|
||||
clearSearch: () => void;
|
||||
placeholder: string;
|
||||
}
|
||||
|
||||
export function SearchInput(props: SearchInputProps) {
|
||||
const { handleSearch, clearSearch, placeholder } = props;
|
||||
|
||||
const [term, setTerm] = useState("");
|
||||
|
||||
const handleSubmit = React.useRef((input: string) => {
|
||||
handleSearch(input);
|
||||
}).current;
|
||||
const debouncedSubmit = useMemo(
|
||||
() => debounce(handleSubmit, 300),
|
||||
[handleSubmit]
|
||||
);
|
||||
|
||||
const handleClear = () => {
|
||||
setTerm("");
|
||||
clearSearch();
|
||||
};
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
setTerm(e.target.value);
|
||||
debouncedSubmit(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper
|
||||
component="form"
|
||||
elevation={0}
|
||||
sx={{
|
||||
width: "100%",
|
||||
p: 1,
|
||||
my: 2,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
onSubmit={(e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
handleSubmit(term);
|
||||
}}
|
||||
>
|
||||
<IconButton aria-label="clear-button" onClick={handleClear}>
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
<InputBase
|
||||
autoFocus
|
||||
sx={{ ml: 1, flex: 1, backgroundColor: "#fff", p: 1 }}
|
||||
placeholder={placeholder}
|
||||
inputProps={{ "aria-label": "search-input" }}
|
||||
value={term}
|
||||
onChange={(e) => handleChange(e)}
|
||||
/>
|
||||
<IconButton
|
||||
type="submit"
|
||||
onClick={() => handleSubmit(term)}
|
||||
sx={{
|
||||
p: 1,
|
||||
bgcolor: "primary.dark",
|
||||
color: "common.white",
|
||||
"&:hover": {
|
||||
backgroundColor: "primary.main",
|
||||
opacity: [0.9, 0.8, 0.7],
|
||||
},
|
||||
}}
|
||||
aria-label="search-button"
|
||||
>
|
||||
<SearchIcon />
|
||||
</IconButton>
|
||||
</Paper>
|
||||
);
|
||||
}
|
7
createEmotionCache.ts
Normal file
7
createEmotionCache.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import createCache from "@emotion/cache";
|
||||
|
||||
const createEmotionCache = () => {
|
||||
return createCache({ key: "css", prepend: true });
|
||||
};
|
||||
|
||||
export default createEmotionCache;
|
286
flake.lock
Normal file
286
flake.lock
Normal file
@ -0,0 +1,286 @@
|
||||
{
|
||||
"nodes": {
|
||||
"alejandra": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"flakeCompat": "flakeCompat",
|
||||
"nixpkgs": [
|
||||
"dream2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1658427149,
|
||||
"narHash": "sha256-ToD/1z/q5VHsLMrS2h96vjJoLho59eNRtknOUd19ey8=",
|
||||
"owner": "kamadorueda",
|
||||
"repo": "alejandra",
|
||||
"rev": "f5a22afd2adfb249b4e68e0b33aa1f0fb73fb1be",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "kamadorueda",
|
||||
"repo": "alejandra",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"all-cabal-json": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1665552503,
|
||||
"narHash": "sha256-r14RmRSwzv5c+bWKUDaze6pXM7nOsiz1H8nvFHJvufc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "all-cabal-json",
|
||||
"rev": "d7c0434eebffb305071404edcf9d5cd99703878e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "hackage",
|
||||
"repo": "all-cabal-json",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"crane": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1661875961,
|
||||
"narHash": "sha256-f1h/2c6Teeu1ofAHWzrS8TwBPcnN+EEu+z1sRVmMQTk=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "d9f394e4e20e97c2a60c3ad82c2b6ef99be19e24",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devshell": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1663445644,
|
||||
"narHash": "sha256-+xVlcK60x7VY1vRJbNUEAHi17ZuoQxAIH4S4iUFUGBA=",
|
||||
"owner": "numtide",
|
||||
"repo": "devshell",
|
||||
"rev": "e3dc3e21594fe07bdb24bdf1c8657acaa4cb8f66",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "devshell",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"dream2nix": {
|
||||
"inputs": {
|
||||
"alejandra": "alejandra",
|
||||
"all-cabal-json": "all-cabal-json",
|
||||
"crane": "crane",
|
||||
"devshell": "devshell",
|
||||
"flake-utils-pre-commit": "flake-utils-pre-commit",
|
||||
"ghc-utils": "ghc-utils",
|
||||
"gomod2nix": "gomod2nix",
|
||||
"mach-nix": "mach-nix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"poetry2nix": "poetry2nix",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1667429039,
|
||||
"narHash": "sha256-Lu6da25JioHzerkLHAHSO9suCQFzJ/XBjkcGCIbasLM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "dream2nix",
|
||||
"rev": "5252794e58eedb02d607fa3187ffead7becc81b0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "dream2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"dream2nix",
|
||||
"alejandra",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1657607339,
|
||||
"narHash": "sha256-HaqoAwlbVVZH2n4P3jN2FFPMpVuhxDy1poNOR7kzODc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "b814c83d9e6aa5a28d0cf356ecfdafb2505ad37d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils-pre-commit": {
|
||||
"locked": {
|
||||
"lastModified": 1644229661,
|
||||
"narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flakeCompat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1650374568,
|
||||
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"ghc-utils": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1662774800,
|
||||
"narHash": "sha256-1Rd2eohGUw/s1tfvkepeYpg8kCEXiIot0RijapUjAkE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "bb3a2d3dc52ff0253fb9c2812bd7aa2da03e0fea",
|
||||
"revCount": 1072,
|
||||
"type": "git",
|
||||
"url": "https://gitlab.haskell.org/bgamari/ghc-utils"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://gitlab.haskell.org/bgamari/ghc-utils"
|
||||
}
|
||||
},
|
||||
"gomod2nix": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1627572165,
|
||||
"narHash": "sha256-MFpwnkvQpauj799b4QTBJQFEddbD02+Ln5k92QyHOSk=",
|
||||
"owner": "tweag",
|
||||
"repo": "gomod2nix",
|
||||
"rev": "67f22dd738d092c6ba88e420350ada0ed4992ae8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "tweag",
|
||||
"repo": "gomod2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"mach-nix": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1634711045,
|
||||
"narHash": "sha256-m5A2Ty88NChLyFhXucECj6+AuiMZPHXNbw+9Kcs7F6Y=",
|
||||
"owner": "DavHau",
|
||||
"repo": "mach-nix",
|
||||
"rev": "4433f74a97b94b596fa6cd9b9c0402104aceef5d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "mach-nix",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1665580254,
|
||||
"narHash": "sha256-hO61XPkp1Hphl4HGNzj1VvDH5URt7LI6LaY/385Eul4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "f634d427b0224a5f531ea5aa10c3960ba6ec5f0f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"poetry2nix": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1632969109,
|
||||
"narHash": "sha256-jPDclkkiAy5m2gGLBlKgH+lQtbF7tL4XxBrbSzw+Ioc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"rev": "aee8f04296c39d88155e05d25cfc59dfdd41cc77",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "1.21.0",
|
||||
"repo": "poetry2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"dream2nix",
|
||||
"flake-utils-pre-commit"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"dream2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1646153636,
|
||||
"narHash": "sha256-AlWHMzK+xJ1mG267FdT8dCq/HvLCA6jwmx2ZUy5O8tY=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "b6bc0b21e1617e2b07d8205e7fae7224036dfa4b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"dream2nix": "dream2nix"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1657557289,
|
||||
"narHash": "sha256-PRW+nUwuqNTRAEa83SfX+7g+g8nQ+2MMbasQ9nt6+UM=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "caf23f29144b371035b864a1017dbc32573ad56d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
30
flake.nix
Normal file
30
flake.nix
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
inputs.dream2nix.url = "github:nix-community/dream2nix";
|
||||
outputs = inp:
|
||||
let
|
||||
inherit (builtins.fromJSON (builtins.readFile ./package.json)) name;
|
||||
in
|
||||
inp.dream2nix.lib.makeFlakeOutputs {
|
||||
systemsFromFile = ./nix_systems;
|
||||
config.projectRoot = ./.;
|
||||
source = ./.;
|
||||
settings = [
|
||||
{
|
||||
subsystemInfo.nodejs = 18;
|
||||
}
|
||||
];
|
||||
packageOverrides = {
|
||||
${name}.staticPage = {
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
npm run export
|
||||
mkdir -p $out/static
|
||||
cp -r ./out/* $out/static/
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
10
next.config.js
Normal file
10
next.config.js
Normal file
@ -0,0 +1,10 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true,
|
||||
images: {
|
||||
loader: "custom",
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
1
nix_systems
Normal file
1
nix_systems
Normal file
@ -0,0 +1 @@
|
||||
x86_64-linux
|
6059
package-lock.json
generated
Normal file
6059
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
package.json
Normal file
28
package.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "nextapp",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"export": "next export",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.5",
|
||||
"@emotion/styled": "^11.10.5",
|
||||
"@fontsource/roboto": "^4.5.8",
|
||||
"@mui/icons-material": "^5.10.9",
|
||||
"@mui/material": "^5.10.13",
|
||||
"@types/node": "18.11.9",
|
||||
"@types/react": "^18.0.25",
|
||||
"@types/react-dom": "18.0.8",
|
||||
"eslint": "8.27.0",
|
||||
"eslint-config-next": "13.0.2",
|
||||
"next": "13.0.2",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"typescript": "4.8.4"
|
||||
}
|
||||
}
|
56
pages/_app.tsx
Normal file
56
pages/_app.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import * as React from "react";
|
||||
import type { AppProps } from "next/app";
|
||||
import { CacheProvider, EmotionCache } from "@emotion/react";
|
||||
import { ThemeProvider, CssBaseline, createTheme } from "@mui/material";
|
||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||
|
||||
import "@fontsource/roboto/300.css";
|
||||
import "@fontsource/roboto/400.css";
|
||||
import "@fontsource/roboto/500.css";
|
||||
import "@fontsource/roboto/700.css";
|
||||
|
||||
import createEmotionCache from "../createEmotionCache";
|
||||
import { lightThemeOptions, darkThemeOptions } from "../styles/theme";
|
||||
import "../styles/globals.css";
|
||||
import { Layout } from "../components/layout";
|
||||
import Head from "next/head";
|
||||
|
||||
interface MyAppProps extends AppProps {
|
||||
emotionCache?: EmotionCache;
|
||||
}
|
||||
|
||||
const clientSideEmotionCache = createEmotionCache();
|
||||
|
||||
const lightTheme = createTheme(lightThemeOptions);
|
||||
const darkTheme = createTheme(darkThemeOptions);
|
||||
|
||||
const MyApp: React.FunctionComponent<MyAppProps> = (props) => {
|
||||
const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;
|
||||
const userPrefersDarkmode = useMediaQuery("(prefers-color-scheme: dark)");
|
||||
|
||||
const getContent = () => {
|
||||
return (
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>noogle</title>
|
||||
<meta name="description" content="Search nix functions" />
|
||||
<link rel="icon" href="/favicon.png" />
|
||||
</Head>
|
||||
|
||||
<CacheProvider value={emotionCache}>
|
||||
<ThemeProvider theme={userPrefersDarkmode ? darkTheme : lightTheme}>
|
||||
<CssBaseline />
|
||||
{getContent()}
|
||||
</ThemeProvider>
|
||||
</CacheProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyApp;
|
450
pages/index.tsx
Normal file
450
pages/index.tsx
Normal file
@ -0,0 +1,450 @@
|
||||
import { BasicList, BasicListItem } from "../components/basicList";
|
||||
import { useState, useMemo } from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import FunctionItem from "../components/functionItem/functionItem";
|
||||
import { NixType } from "../types/basicDataView";
|
||||
import { Preview } from "../components/preview/preview";
|
||||
|
||||
const libfuns = {
|
||||
mapAttrs: {
|
||||
"attr-path": "builtins.mapAttrs",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nix/stable/language/builtins.html#builtins-mapAttrs",
|
||||
source: "builtin",
|
||||
from: "attrset",
|
||||
to: "attrset",
|
||||
},
|
||||
"mapAttrs'": {
|
||||
"attr-path": "lib.mapAttrs'",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-attrset",
|
||||
source: "nixpkgs",
|
||||
from: "attrset",
|
||||
to: "attrset",
|
||||
},
|
||||
toString: {
|
||||
"attr-path": "builtins.toString'",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nix/stable/language/builtins.html#builtins-toString",
|
||||
source: "builtin",
|
||||
from: "any",
|
||||
to: "string",
|
||||
},
|
||||
genAttrs: {
|
||||
"attr-path": "lib.genAttrs",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-attrset",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "attrset",
|
||||
},
|
||||
|
||||
forEach: {
|
||||
"attr-path": "lib.forEach",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
foldr: {
|
||||
"attr-path": "lib.foldr",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "any",
|
||||
},
|
||||
foldl: {
|
||||
"attr-path": "lib.foldl",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "any",
|
||||
},
|
||||
"foldl'": {
|
||||
"attr-path": "lib.foldl'",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "any",
|
||||
},
|
||||
imap0: {
|
||||
"attr-path": "lib.imap0",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
imap1: {
|
||||
"attr-path": "lib.imap1",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
concatMap: {
|
||||
"attr-path": "lib.concatMap",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
flatten: {
|
||||
"attr-path": "lib.flatten",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
remove: {
|
||||
"attr-path": "lib.remove",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
findSingle: {
|
||||
"attr-path": "lib.findSingle",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "any",
|
||||
},
|
||||
findFirst: {
|
||||
"attr-path": "lib.findFirst",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "any",
|
||||
},
|
||||
any: {
|
||||
"attr-path": "lib.any",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "true",
|
||||
},
|
||||
all: {
|
||||
"attr-path": "lib.all",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "true",
|
||||
},
|
||||
count: {
|
||||
"attr-path": "lib.count",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "int",
|
||||
},
|
||||
optional: {
|
||||
"attr-path": "lib.optional",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "bool",
|
||||
to: "list",
|
||||
},
|
||||
optionals: {
|
||||
"attr-path": "lib.optionals",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "bool",
|
||||
to: "list",
|
||||
},
|
||||
toList: {
|
||||
"attr-path": "lib.toList",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "any",
|
||||
to: "list",
|
||||
},
|
||||
range: {
|
||||
"attr-path": "lib.range",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "int",
|
||||
to: "list",
|
||||
},
|
||||
partition: {
|
||||
"attr-path": "lib.partition",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
"groupBy'": {
|
||||
"attr-path": "lib.groupBy'",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
groupBy: {
|
||||
"attr-path": "lib.groupBy",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
zipListsWith: {
|
||||
"attr-path": "lib.zipListsWith",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
zipLists: {
|
||||
"attr-path": "lib.zipLists",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
reverseList: {
|
||||
"attr-path": "lib.reverseList",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
listDfs: {
|
||||
"attr-path": "lib.listDfs",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "attrset",
|
||||
},
|
||||
toposort: {
|
||||
"attr-path": "lib.toposort",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
sort: {
|
||||
"attr-path": "lib.sort",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
compareLists: {
|
||||
"attr-path": "lib.compareLists",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "int",
|
||||
},
|
||||
naturalSort: {
|
||||
"attr-path": "lib.naturalSort",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
take: {
|
||||
"attr-path": "lib.take",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
sublist: {
|
||||
"attr-path": "lib.sublist",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
last: {
|
||||
"attr-path": "lib.last",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "any",
|
||||
},
|
||||
init: {
|
||||
"attr-path": "lib.init",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
crossLists: {
|
||||
"attr-path": "lib.crossLists",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
unique: {
|
||||
"attr-path": "lib.unique",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
intersectLists: {
|
||||
"attr-path": "lib.intersectLists",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
subtractLists: {
|
||||
"attr-path": "lib.subtractLists",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "list",
|
||||
},
|
||||
mutuallyExclusive: {
|
||||
"attr-path": "lib.mutuallyExclusive",
|
||||
"doc-url":
|
||||
"https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-lists",
|
||||
source: "nixpkgs",
|
||||
from: "list",
|
||||
to: "bool",
|
||||
},
|
||||
};
|
||||
|
||||
export type FuncData = {
|
||||
name: string;
|
||||
info: {
|
||||
"attr-path": string;
|
||||
"doc-url": string;
|
||||
source: string;
|
||||
from: string;
|
||||
to: string;
|
||||
};
|
||||
};
|
||||
|
||||
const mockData: FuncData[] = Object.entries(libfuns).map(([key, value]) => ({
|
||||
name: key,
|
||||
info: value,
|
||||
}));
|
||||
|
||||
const pipe =
|
||||
(...fns: ((arr: FuncData[]) => FuncData[])[]) =>
|
||||
(x: FuncData[]) =>
|
||||
fns.reduce((v, f) => f(v), x);
|
||||
|
||||
const search =
|
||||
(term: string) =>
|
||||
(data: FuncData[]): FuncData[] => {
|
||||
return data.filter((item) => {
|
||||
return Object.values(item).some((value) => {
|
||||
const valueAsString = value.toString();
|
||||
return valueAsString.toLowerCase().includes(term.toLocaleLowerCase());
|
||||
});
|
||||
});
|
||||
};
|
||||
const filter =
|
||||
(to: NixType, from: NixType) =>
|
||||
(data: FuncData[]): FuncData[] => {
|
||||
return data.filter(({ info }) => info.from === from && info.to === to);
|
||||
};
|
||||
|
||||
export default function FunctionsPage() {
|
||||
// const [visibleFuncs, setVisibleFuncs] = useState(mockData);
|
||||
const [selected, setSelected] = useState<string | null>(null);
|
||||
const [term, setTerm] = useState<string>("");
|
||||
const [to, setTo] = useState<NixType>("any");
|
||||
const [from, setFrom] = useState<NixType>("any");
|
||||
|
||||
const handleSelect = (key: string) => {
|
||||
setSelected((curr) => {
|
||||
if (curr === key) {
|
||||
return null;
|
||||
} else {
|
||||
return key;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const filteredData = useMemo(
|
||||
() => pipe(filter(to, from), search(term))(mockData),
|
||||
[to, from, term]
|
||||
);
|
||||
|
||||
const handleSearch = (term: string) => {
|
||||
setTerm(term);
|
||||
};
|
||||
|
||||
const handleFilter = (t: NixType, mode: "to" | "from") => {
|
||||
if (mode === "from") {
|
||||
setFrom(t);
|
||||
}
|
||||
if (mode === "to") {
|
||||
setTo(t);
|
||||
}
|
||||
};
|
||||
|
||||
const preRenderedItems: BasicListItem[] = filteredData.map(
|
||||
({ name, info }) => ({
|
||||
item: (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
onClick={() => handleSelect(name)}
|
||||
>
|
||||
<FunctionItem name={name} info={info} selected={selected === name} />
|
||||
</Box>
|
||||
),
|
||||
key: name,
|
||||
})
|
||||
);
|
||||
const preview = (
|
||||
<Preview func={mockData.find((f) => f.name === selected) || mockData[0]} />
|
||||
);
|
||||
|
||||
return (
|
||||
<Box sx={{ ml: 2 }}>
|
||||
<BasicList
|
||||
items={preRenderedItems}
|
||||
handleSearch={handleSearch}
|
||||
handleFilter={handleFilter}
|
||||
preview={selected ? preview : null}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
public/favicon.png
Normal file
BIN
public/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
4
public/vercel.svg
Normal file
4
public/vercel.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
21
styles/globals.css
Normal file
21
styles/globals.css
Normal file
@ -0,0 +1,21 @@
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: rgb(242, 248, 253);
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
||||
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.react-terminal-wrapper:before {
|
||||
background: unset !important;
|
||||
}
|
16
styles/theme/darkThemeOptions.ts
Normal file
16
styles/theme/darkThemeOptions.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ThemeOptions } from "@mui/material/styles";
|
||||
|
||||
const darkThemeOptions: ThemeOptions = {
|
||||
palette: {
|
||||
mode: "dark",
|
||||
primary: {
|
||||
main: "#6586c8"
|
||||
|
||||
},
|
||||
secondary: {
|
||||
main: "#6ad541"
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export { darkThemeOptions };
|
2
styles/theme/index.tsx
Normal file
2
styles/theme/index.tsx
Normal file
@ -0,0 +1,2 @@
|
||||
export { lightThemeOptions } from "./lightThemeOptions";
|
||||
export { darkThemeOptions } from "./darkThemeOptions";
|
16
styles/theme/lightThemeOptions.ts
Normal file
16
styles/theme/lightThemeOptions.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ThemeOptions } from "@mui/material/styles";
|
||||
|
||||
const lightThemeOptions: ThemeOptions = {
|
||||
palette: {
|
||||
mode: "light",
|
||||
primary: {
|
||||
main: "#6586c8"
|
||||
|
||||
},
|
||||
secondary: {
|
||||
main: "#6ad541"
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export { lightThemeOptions };
|
20
tsconfig.json
Normal file
20
tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
12
types/basicDataView.ts
Normal file
12
types/basicDataView.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export type BasicDataItem = {
|
||||
item: React.ReactNode;
|
||||
key: string;
|
||||
};
|
||||
|
||||
export type BasicDataViewProps = {
|
||||
items: BasicDataItem[];
|
||||
pageCount?: number;
|
||||
handleSearch?: (term: string) => void;
|
||||
};
|
||||
|
||||
export type NixType = "attrset" | "list" | "string" | "int" | "bool" | "any";
|
Loading…
Reference in New Issue
Block a user