Added basic application design with material design
This commit is contained in:
parent
60724dfa60
commit
a9ecf32a56
36
src/App.tsx
36
src/App.tsx
@ -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
23
src/AppBar.tsx
Normal 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
27
src/Layout.tsx
Normal 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
41
src/TodoItem.tsx
Normal 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
20
src/TodoList.tsx
Normal 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
20
src/hooks.ts
Normal 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,
|
||||
};
|
||||
};
|
@ -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;
|
||||
}
|
@ -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
5
src/types.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export type TaskItemT = {
|
||||
id: number;
|
||||
text: string;
|
||||
done: boolean;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user