Added basic application design with material design

This commit is contained in:
Dmitriy Shishkov 2021-10-11 13:53:17 +03:00
parent 60724dfa60
commit a9ecf32a56
No known key found for this signature in database
GPG Key ID: 14358F96FCDD8060
9 changed files with 170 additions and 33 deletions

View File

@ -1,3 +1,35 @@
import React from "react";
import React, { useMemo } from "react";
import CssBaseline from "@mui/material/CssBaseline";
import useMediaQuery from "@mui/material/useMediaQuery";
import { createTheme, ThemeProvider } from "@mui/material/styles";
export const App = () => <div>Hello, world</div>;
import { Layout } from "./Layout";
import { TodoList } from "./TodoList";
import { AppBar } from "./AppBar";
import { TaskItemT } from "./types";
const tasks: TaskItemT[] = [
{ text: "test", done: false, id: 0 },
{ text: "Long, a bit tooooooo0000000000oooooo long test", done: true, id: 1 },
];
export const App = () => {
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
const theme = useMemo(
() =>
createTheme({ palette: { mode: prefersDarkMode ? "dark" : "light" } }),
[prefersDarkMode]
);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Layout
appBar={<AppBar />}
title="My tasks"
content={<TodoList tasks={tasks} />}
/>
</ThemeProvider>
);
};

23
src/AppBar.tsx Normal file
View File

@ -0,0 +1,23 @@
import { Fab, Box } from "@mui/material";
import Add from "@mui/icons-material/Add";
import React from "react";
/* TODO: create component for task adding */
export const AppBar: React.FC = () => (
<Box sx={{ width: "100%", justifyContent: "center", display: "flex" }}>
<Fab
variant="extended"
color="primary"
aria-label="add"
sx={{
position: "relative",
zIndex: 1,
top: -30,
}}
>
<Add sx={{ marginRight: 1 }} />
Add a new task
</Fab>
</Box>
);

27
src/Layout.tsx Normal file
View File

@ -0,0 +1,27 @@
import { AppBar, Box, Toolbar, Typography, Checkbox } from "@mui/material";
import React, { ReactNode } from "react";
export type LayoutProps = {
appBar: ReactNode;
content: ReactNode;
title: string;
};
export const Layout: React.FC<LayoutProps> = ({ appBar, content, title }) => (
<>
<Box sx={{ padding: (theme) => theme.spacing(2, 2, 10, 2) }}>
<Typography variant="h4" sx={{ paddingLeft: 2, marginBottom: 2 }}>
<Checkbox sx={{ visibility: "hidden" }} />
{title}
</Typography>
{content}
</Box>
<AppBar
position="fixed"
color="transparent"
sx={{ top: "auto", bottom: 0 }}
>
<Toolbar>{appBar}</Toolbar>
</AppBar>
</>
);

41
src/TodoItem.tsx Normal file
View File

@ -0,0 +1,41 @@
import {
Checkbox,
IconButton,
ListItem,
ListItemSecondaryAction,
ListItemText,
TextField,
} from "@mui/material";
import DeleteOutlined from "@mui/icons-material/DeleteOutlined";
import React, { useState } from "react";
import { TaskItemT } from "./types";
export type TodoItemProps = { task: TaskItemT };
export const TodoItem: React.FC<TodoItemProps> = ({ task }) => {
const { done, text } = task;
const [editing, setEditing] = useState(false);
return (
<ListItem>
<Checkbox checked={done} />
{editing ? (
<TextField
fullWidth
variant="standard"
value={text}
autoFocus={true}
onBlur={() => setEditing(false)}
></TextField>
) : (
<ListItemText onClick={() => setEditing(true)} primary={text} />
)}
<ListItemSecondaryAction>
<IconButton aria-label="Delete Todo">
<DeleteOutlined />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
);
};

20
src/TodoList.tsx Normal file
View File

@ -0,0 +1,20 @@
import { List, Paper } from "@mui/material";
import React from "react";
import { TodoItem } from "./TodoItem";
import { TaskItemT } from "./types";
export type TodoListProps = {
tasks: TaskItemT[];
};
export const TodoList: React.FC<TodoListProps> = ({ tasks }) => {
return (
<Paper variant="outlined">
<List>
{tasks.map((task) => (
<TodoItem key={task.id} task={task} />
))}
</List>
</Paper>
);
};

20
src/hooks.ts Normal file
View File

@ -0,0 +1,20 @@
import { ChangeEventHandler, useState } from "react";
export type UseInputValueReturnT = {
onChange: ChangeEventHandler<HTMLInputElement>;
submit: () => void;
value: string;
};
export const useInputValue = (
initialValue: string = "",
onSubmit: (value: string) => void
): UseInputValueReturnT => {
const [value, setValue] = useState(initialValue);
return {
onChange: (e) => setValue(e.currentTarget.value),
submit: () => onSubmit(value),
value,
};
};

View File

@ -1,25 +0,0 @@
* {
margin: 0;
padding: 0;
-ms-overflow-style: none;
scrollbar-width: none;
box-sizing: border-box;
outline: none;
}
*::-webkit-scrollbar {
display: none;
}
body {
font-family: Inter, system-ui, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: rgba(54, 54, 69, 0.05) none repeat scroll 0% 0%;
color: rgb(54, 54, 69);
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}

View File

@ -1,8 +1,6 @@
import React from "react";
import ReactDOM from "react-dom";
import './index.css'
import { App } from "./App";
ReactDOM.render(
@ -11,7 +9,3 @@ ReactDOM.render(
</React.StrictMode>,
document.getElementById("root")
);
if (import.meta.hot) {
import.meta.hot.accept();
}

5
src/types.ts Normal file
View File

@ -0,0 +1,5 @@
export type TaskItemT = {
id: number;
text: string;
done: boolean;
};