first commit

This commit is contained in:
Romulus21
2021-12-17 15:37:05 +01:00
commit 2d49672d20
43 changed files with 39806 additions and 0 deletions

38
src/components/App.js Normal file
View File

@@ -0,0 +1,38 @@
import { h } from 'preact';
import { Router } from 'preact-router';
import ContextsProviders from '../Contexts';
import Header from './Header';
// Code-splitting is automated for `routes` directory
import Home from '../routes/Home';
import Plant from '../routes/Plant';
import Profile from '../routes/Profile';
import {useEffect} from "preact/hooks";
const App = () => {
useEffect(() => {
if (!Notification) {
alert('Le navigateur ne supporte pas les notifications.');
} else if (Notification.permission !== 'granted') {
Notification.requestPermission();
}
}, [])
return (
<div id="app" class="h-screen overflow-auto flex flex-col">
<ContextsProviders>
<Header />
<main className="flex-1 dark:bg-gray-800 dark:text-white">
<Router>
<Home path="/" />
<Plant path="plant/:id" />
<Profile path="/profile" />
</Router>
</main>
</ContextsProviders>
</div>
)}
export default App;

10
src/components/Button.js Normal file
View File

@@ -0,0 +1,10 @@
import { classNames } from "../utilities/classNames"
export const Button = ({ children, className = "", type = "text", ...props }) => {
return (
<button type={type} className={classNames("border px-2 py-1 shadow rounded", className)} {...props}>
{children}
</button>
)
}

59
src/components/Form.js Normal file
View File

@@ -0,0 +1,59 @@
import {classNames} from "../utilities/classNames";
export const InputField = ({children, name, type = "text", ...props}) => {
const id = props.id ?? name
const classStyle = props.className ?? ''
if (props.className) {
delete props.className
}
return <fieldset className={classNames(classStyle)}>
{children && <label htmlFor={id} className="block text-sm font-medium text-gray-700 dark:text-gray-300">
{ children }
</label>}
<input id={id}
name={name}
type={type}
className="focus:ring-indigo-500 focus:border-indigo-500 block w-full px-2 py-1 mt-1 sm:text-sm border border-gray-300 rounded-md dark:bg-gray-500"
{...props}/>
</fieldset>
}
export const TextAreaField = ({children, name, ...props}) => {
const id = props.id ?? name
const classStyle = props.className ?? ''
if (props.className) {
delete props.className
}
return <fieldset className={classNames(classStyle)}>
{children && <label htmlFor={id} className="block text-sm font-medium text-gray-700 dark:text-gray-300">
{ children }
</label>}
<textarea id={id}
name={name}
className="focus:ring-indigo-500 focus:border-indigo-500 block w-full px-2 py-1 mt-1 sm:text-sm border border-gray-300 dark:bg-gray-500 rounded-md"
{...props}
/>
</fieldset>
}
export const SelectField = ({children, name, options, className = '', ...props}) => {
const id = props.id ?? name
return <fieldset className={className}>
{children && <label htmlFor={id} className="block text-sm font-medium text-gray-700 dark:text-gray-300">
{ children }
</label>}
<select id={id} name={name} className="focus:ring-indigo-500 focus:border-indigo-500 block w-full px-2 py-1 mt-1 sm:text-sm border border-gray-300 dark:bg-gray-500 rounded-md" {...props}>
{options.map((option, index) => <option key={index} value={option}
className="capitalize">{option}</option>)}
</select>
</fieldset>
}

29
src/components/Header.js Normal file
View File

@@ -0,0 +1,29 @@
import { h } from "preact"
import { Link } from "preact-router/match"
const Header = () => {
return (
<header class="bg-green-700 text-white flex justify-between items-center p-2 text-lg">
<Link href="/" class="font-bold text-xl">
Plantes
</Link>
<nav class="flex">
<NavLink path="/profile">Me</NavLink>
</nav>
</header>
)
}
export default Header
const NavLink = ({ path, children }) => {
return (
<Link
href={path}
activeClassName="font-bold bg-green-800"
class="py-1 px-2 rounded"
>
{children}
</Link>
)
}

28
src/components/Modals.js Normal file
View File

@@ -0,0 +1,28 @@
import { classNames } from "../utilities/classNames"
export const Modal = ({children, isOpen, customClose = false, ...props}) => {
const handleClose = e => props.onChange(e)
return <>
{isOpen &&
<div className="overlay fixed block top-0 bottom-0 left-0 right-0 z-10 bg-gray-800 bg-opacity-80" onClick={handleClose}>
<div className="h-full flex justify-center items-center">
<div className="flex flex-col bg-white dark:bg-gray-700 dark:text-white rounded p-2 min-h-48 min-w-48" {...props}>
<div className="flex-1">
{children}
</div>
{!customClose &&<div className="flex justify-end">
<button type="button" className="bg-gray-300 dark:bg-gray-600 hover:bg-gray-400 hover:dark:bg-gray-800 px-2 py-1 rounded shadow close-button" onClick={handleClose}>Close</button>
</div>}
</div>
</div>
</div>
}
</>
}
export const ModalTitle = ({children, ...props}) => {
return <div className="bg-green-700 text-white text-2xl font-bold text-center -mx-2 -mt-2 p-2 rounded-tl rounded-tr" {...props}>{children}</div>
}

View File

@@ -0,0 +1,9 @@
import { classNames } from "../utilities/classNames";
export const PageLayout = ({children, ...props}) => {
return <div class={classNames("p-2", props.class ?? "")}>
{children}
</div>
}

17
src/components/Plants.js Normal file
View File

@@ -0,0 +1,17 @@
import { Link } from "preact-router/match"
import {getPicture} from "../utilities/pictures";
export const PlantThumb = ({ plant, children }) => {
return <Link href={`/plant/${plant.id}`} class="block h-48">
<div className="bg-green-400 relative rounded shadow-lg flex flex-col">
<img src={getPicture(plant.id)} alt="" className="object-cover h-48 w-full rounded" />
<div className="bg-green-700 text-white p-2 text-center absolute bottom-0 w-full rounded-bl rounded-br">
{children}
</div>
<div title="Actions" className="absolute right-2 top-2 rounded-full flex justify-center items-center bg-green-700 w-6 h-6">
{plant.actions.length}
</div>
</div>
</Link>
}

27
src/components/Tasks.js Normal file
View File

@@ -0,0 +1,27 @@
import {Button} from "./Button"
import {useContext} from "preact/hooks"
import {PlantsContext} from "../Contexts"
export const Tasks = () => {
const { plants, doneTask, history } = useContext(PlantsContext)
const taskIsRequired = (action) => {
if (history()[action.id]) {
let lastTask = new Date(history()[action.id])
return lastTask.addDays(Number(action.frequency)) < (new Date())
}
return true
}
return <div className="mb-5">
<h1>Tasks</h1>
<div>
{plants.map(plant => plant.actions.filter(action => taskIsRequired(action)).map(action => <div className="flex items-center gap-2">
<span className="capitalize"><b>{plant.name}</b> {action.action_type}</span>
<span> every {action.frequency} days {action.id}</span>
<span><Button onClick={() => doneTask(action.id)}>Done</Button></span>
</div>))}
</div>
</div>
}