add lang
This commit is contained in:
@@ -8,20 +8,12 @@ import Header from './Header';
|
||||
import Home from '../routes/Home';
|
||||
import Plant from '../routes/Plant';
|
||||
import Profile from '../routes/Profile';
|
||||
import {useEffect} from "preact/hooks";
|
||||
import Style from "../routes/Style";
|
||||
|
||||
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">
|
||||
<div id="app" className="h-screen overflow-auto flex flex-col">
|
||||
<ContextsProviders>
|
||||
<Header />
|
||||
<main className="flex-1 dark:bg-gray-800 dark:text-white">
|
||||
@@ -29,6 +21,7 @@ const App = () => {
|
||||
<Home path="/" />
|
||||
<Plant path="plant/:id" />
|
||||
<Profile path="/profile" />
|
||||
<Style path="/style" />
|
||||
</Router>
|
||||
</main>
|
||||
</ContextsProviders>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { classNames } from "../utilities/classNames"
|
||||
|
||||
export const Button = ({ children, className = "", type = "text", ...props }) => {
|
||||
export const Button = ({ children, className = "", type = "button", ...props }) => {
|
||||
|
||||
return (
|
||||
<button type={type} className={classNames("border px-2 py-1 shadow transition-all duration-300 rounded", className)} {...props}>
|
||||
<button type={type} className={classNames("border px-2 py-1 shadow transition-all duration-300 rounded hover:ring-2 focus:ring-2 ring-offset disabled:opacity-50 disabled:cursor-not-allowed", className)} {...props}>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {classNames} from "../utilities/classNames";
|
||||
import {Text} from "./Translation";
|
||||
|
||||
export const InputField = ({children, name, value = "", type = "text", textSupport = "", ...props}) => {
|
||||
|
||||
@@ -19,7 +20,7 @@ export const InputField = ({children, name, value = "", type = "text", textSuppo
|
||||
value={value}
|
||||
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}/>
|
||||
<span className="text-gray-500 text-sm">{textSupport}</span>
|
||||
<span className="text-gray-500 text-sm"><Text text={textSupport} /></span>
|
||||
</fieldset>
|
||||
}
|
||||
|
||||
@@ -54,7 +55,7 @@ export const SelectField = ({children, name, options, className = '', ...props})
|
||||
</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>)}
|
||||
className="capitalize"><Text text={option} /></option>)}
|
||||
</select>
|
||||
</fieldset>
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import { h } from "preact"
|
||||
import { Link } from "preact-router/match"
|
||||
import {Text} from "./Translation"
|
||||
|
||||
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
|
||||
<header className="bg-primary text-white flex justify-between items-center p-2 text-lg">
|
||||
<Link href="/" class="font-bold text-xl cursor-pointer">
|
||||
<Text text="Plantes" />
|
||||
</Link>
|
||||
<nav class="flex">
|
||||
<NavLink path="/profile">Me</NavLink>
|
||||
<nav className="flex gap-2">
|
||||
<NavLink path="/style"><Text text="Style" /></NavLink>
|
||||
<NavLink path="/profile"><Text text="Me" /></NavLink>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
@@ -20,8 +21,8 @@ const NavLink = ({ path, children }) => {
|
||||
return (
|
||||
<Link
|
||||
href={path}
|
||||
activeClassName="font-bold bg-green-800"
|
||||
class="py-1 px-2 rounded"
|
||||
activeClassName="font-bold bg-primary-dark"
|
||||
class="py-1 px-2 rounded cursor-pointer"
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {Text} from "./Translation";
|
||||
|
||||
export const Modal = ({children, isOpen, customClose = false, ...props}) => {
|
||||
|
||||
@@ -7,16 +8,15 @@ export const Modal = ({children, isOpen, customClose = false, ...props}) => {
|
||||
{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 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}><Text text="Close" /></button>
|
||||
</div>}
|
||||
</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>
|
||||
}
|
||||
</>
|
||||
|
||||
@@ -3,16 +3,17 @@ import {getPicture} from "../utilities/pictures"
|
||||
import {InputField, TextAreaField} from "./Form"
|
||||
import {Button} from "./Button"
|
||||
import {useState} from "preact/hooks"
|
||||
import {Text} from "./Translation"
|
||||
|
||||
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">
|
||||
return <Link href={`/plant/${plant.id}`} class="block h-48 cursor-pointer">
|
||||
<div className="group bg-primary-light relative rounded shadow-lg flex flex-col">
|
||||
<img src={getPicture(plant.id)} alt="" className="object-cover h-48 w-full min-h-48 min-w-48 rounded" />
|
||||
<div className="bg-green-700 text-white p-2 text-center absolute bottom-0 w-full rounded-bl rounded-br">
|
||||
<div className="bg-primary group-hover:bg-primary-dark 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">
|
||||
<div title="Actions" className="absolute right-2 top-2 rounded-full flex justify-center items-center bg-primary group-hover:bg-primary-dark w-6 h-6">
|
||||
{plant.actions.length}
|
||||
</div>
|
||||
</div>
|
||||
@@ -29,13 +30,13 @@ export const PlantForm = ({children, plant, ...props}) => {
|
||||
className="mb-2 mt-5"
|
||||
value={plantForm.name}
|
||||
onChange={(e) => setPlantForm({ ...plantForm, name: e.target.value }) }>
|
||||
Name
|
||||
<Text text="Name" />
|
||||
</InputField>
|
||||
<TextAreaField name="description"
|
||||
className="mb-5"
|
||||
value={plantForm.description}
|
||||
onChange={(e) => setPlantForm({ ...plantForm, description: e.target.value })}>
|
||||
Description
|
||||
<Text text="Description" />
|
||||
</TextAreaField>
|
||||
|
||||
<fieldset className="mb-5 flex gap-2 max-w-[300px] mx-auto">
|
||||
@@ -48,7 +49,7 @@ export const PlantForm = ({children, plant, ...props}) => {
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<label htmlFor="indoor" className="w-full block peer-checked:bg-blue-700 bg-blue-500 hover:bg-blue-700 px-2 py-1 text-center rounded border dark:border-white">
|
||||
Indoor
|
||||
<Text text="Indoor" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -61,7 +62,7 @@ export const PlantForm = ({children, plant, ...props}) => {
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<label htmlFor="outdoor" className="w-full block peer-checked:bg-blue-700 bg-blue-500 hover:bg-blue-700 px-2 py-1 text-center rounded border dark:border-white">
|
||||
Outdoor
|
||||
<Text text="Outdoor" />
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -70,7 +71,7 @@ export const PlantForm = ({children, plant, ...props}) => {
|
||||
className="mt-5"
|
||||
value={plantForm.spot}
|
||||
onChange={(e) => setPlantForm({ ...plantForm, spot: e.target.value }) }>
|
||||
Spot
|
||||
<Text text="Spot" />
|
||||
</InputField>
|
||||
|
||||
<Button type="submit" className="block w-full mt-5 mb-2 bg-green-800 hover:bg-green-900 text-white mx-auto px-2 py-1 shadow">
|
||||
|
||||
@@ -2,6 +2,7 @@ import {Button} from "./Button"
|
||||
import { Link } from "preact-router/match"
|
||||
import {useContext} from "preact/hooks"
|
||||
import {PlantsContext} from "../Contexts"
|
||||
import {Text} from "./Translation"
|
||||
|
||||
export const Tasks = () => {
|
||||
|
||||
@@ -19,18 +20,34 @@ export const Tasks = () => {
|
||||
return true
|
||||
}
|
||||
|
||||
const taskDelay = (action) => {
|
||||
if (history()[action.id]) {
|
||||
let lastTask = new Date(history()[action.id])
|
||||
const oneDay = 1000 * 60 * 60 * 24
|
||||
return Math.round(((new Date()) - lastTask)/oneDay)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
return <div className="mb-5">
|
||||
<h1>Tasks</h1>
|
||||
<h1>
|
||||
<Text text="Tasks" />
|
||||
</h1>
|
||||
<div>
|
||||
{plants.map(plant => plant.actions.filter(action => taskIsRequired(action)).map(action => <div className="flex items-center gap-2 my-2">
|
||||
<span><Button className="bg-blue-500 hover:bg-blue-700" onClick={() => doneTask(action.id)}>Done</Button></span>
|
||||
<span>
|
||||
<Button className="bg-blue-500 hover:bg-blue-700" onClick={() => doneTask(action.id)}>
|
||||
<Text text="Done" />
|
||||
</Button>
|
||||
</span>
|
||||
<span className="capitalize">
|
||||
<Link href={`/plant/${plant.id}`} class="font-bold mr-2">{plant.name}</Link>
|
||||
{action.action_type}
|
||||
<Text text={action.action_type} />
|
||||
</span>
|
||||
{Number(action.frequency) === 0
|
||||
? <span>when you want</span>
|
||||
: <span> every {action.frequency} days</span>}
|
||||
? <span><Text text="when you want" /></span>
|
||||
: (taskDelay(action) > 1 ? <span><Text text="since {{count}} days" count={taskDelay(action)} /></span>
|
||||
: <span><Text text="every {{count}} days" count={action.frequency} /></span>)}
|
||||
</div>))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
47
src/components/Translation.js
Normal file
47
src/components/Translation.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import {en} from "../lang/en"
|
||||
import {fr} from "../lang/fr"
|
||||
import {useContext, useEffect, useState} from "preact/hooks"
|
||||
import {createContext} from "preact"
|
||||
|
||||
export const TranslateContext = createContext(null)
|
||||
|
||||
export const Text = ({text, count = null}) => {
|
||||
|
||||
const lang = useContext(TranslateContext)
|
||||
const [translate, setTranslate] = useState()
|
||||
|
||||
useEffect(() => {
|
||||
if (lang && lang[text]) {
|
||||
if (count > 1 && lang[text].many) {
|
||||
text = lang[text].many
|
||||
} else if (count <= 1 && lang[text].one) {
|
||||
text = lang[text].one
|
||||
} else {
|
||||
text = lang[text]
|
||||
}
|
||||
}
|
||||
|
||||
if (count && text.includes('{{count}}')) {
|
||||
text = text.replace('{{count}}', count)
|
||||
}
|
||||
setTranslate(text)
|
||||
}, [])
|
||||
|
||||
return <>{ translate }</>
|
||||
}
|
||||
|
||||
export const TranslateProvider = ({children}) => {
|
||||
|
||||
const userLang = navigator.language || navigator.userLanguage
|
||||
let translate = null
|
||||
if (userLang === "en") {
|
||||
translate = en
|
||||
} else if (userLang === "fr") {
|
||||
translate = fr
|
||||
}
|
||||
|
||||
return <TranslateContext.Provider value={translate}>
|
||||
{ children }
|
||||
</TranslateContext.Provider>
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user