diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-02-20 16:11:50 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-02-20 16:15:08 +0100 |
| commit | 73a5c7fae9ffbe9ada721148c8c454a643aceebe (patch) | |
| tree | c8fad013ed9b5dd589add87f8d45cf02bbfc6e91 /public/projects/react-small-apps/apps/notebook/src/components/layout/Page | |
| parent | b01239fbdcc5bbc5921f73ec0e8fee7bedd5c8e8 (diff) | |
chore!: restructure repo
I separated public files from the config/dev files. It improves repo
readability.
I also moved dotenv helper to public/inc directory and extract the
Matomo tracker in the same directory.
Diffstat (limited to 'public/projects/react-small-apps/apps/notebook/src/components/layout/Page')
4 files changed, 247 insertions, 0 deletions
diff --git a/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/Cover.css b/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/Cover.css new file mode 100644 index 0000000..bf915dd --- /dev/null +++ b/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/Cover.css @@ -0,0 +1,30 @@ +.notebook--cover .notebook-page--mirror { + display: none; +} + +.notebook--cover .notebook-page { + grid-column: 1 / -1; + background: hsl(0, 4%, 20%); + color: rgb(234, 235, 236); + letter-spacing: 1px; + text-shadow: 1px 1px 0 #000; + box-shadow: none; +} + +.notebook--cover .notebook-page { + justify-content: center; + text-align: center; +} + +.notebook--cover .notebook-page__title { + font-size: 3rem; + font-weight: 600; +} + +.notebook--cover .notebook-page .notebook-page__content { + flex: 0; +} + +.notebook--cover .notebook-page .notebook-page__title .form__input { + text-align: center; +} diff --git a/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/Page.css b/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/Page.css new file mode 100644 index 0000000..873df47 --- /dev/null +++ b/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/Page.css @@ -0,0 +1,83 @@ +.notebook-page { + display: flex; + flex-flow: column nowrap; + padding: clamp(1rem, 3vw, 2rem) 0; + background: #fff; + border: 1px solid #cacaca; + box-shadow: 1px 1px 0 0 #ebebeb, 1px 1px 0 1px #bebebe, 2px 2px 0 1px #ebebeb, + 2px 2px 0 2px #bebebe, 3px 3px 0 2px #ebebeb, 3px 3px 0 3px #bebebe; +} + +.notebook-page--mirror { + box-shadow: -1px 1px 0 0 #ebebeb, -1px 1px 0 1px #bebebe, + -2px 2px 0 1px #ebebeb, -2px 2px 0 2px #bebebe, -3px 3px 0 2px #ebebeb, + -3px 3px 0 3px #bebebe; +} + +@media screen and (max-width: 1023px) { + .notebook-page { + grid-column: 1/-1; + } + .notebook-page--mirror { + display: none; + } +} + +.notebook-page__header, +.notebook-page__footer, +.notebook-page__content { + padding: 0 3rem 0 2rem; +} + +.notebook-page__title { + font-size: 1.8rem; + font-weight: 600; + margin: 1rem 0 0; +} + +.notebook-page__title .form__input { + border: none; + font-weight: inherit; + padding: 0; + width: 100%; +} + +.notebook-page__title .form__input:focus { + outline: none; +} + +.notebook-page__content { + flex: 1; + display: flex; + margin: clamp(1rem, 3vw, 2rem) 0 clamp(2rem, 3vw, 3rem); + white-space: pre-wrap; + word-break: break-all; + hyphens: auto; +} + +.notebook-page__content .form__textarea { + border: none; + line-height: inherit; + width: 100%; + height: 100%; + overflow: hidden; + padding: 0; +} + +.notebook-page__content .form__textarea:focus { + outline: none; + resize: none; +} + +.notebook-page__footer { + text-align: right; +} + +.notebook-page__toolbar { + display: flex; + flex-flow: row; + gap: 1rem; + position: absolute; + top: -4rem; + right: 1rem; +} diff --git a/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/Page.js b/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/Page.js new file mode 100644 index 0000000..19e072c --- /dev/null +++ b/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/Page.js @@ -0,0 +1,107 @@ +import { useEffect, useRef } from "react"; +import { Input, TextArea } from "../../commons"; +import useToggle from "../../helpers/hooks/useToggle"; +import PageToolbar from "./PageToolbar"; +import "./Cover.css"; +import "./Page.css"; + +function Page({ page, setPage, removePage, restorePage, deletedPages }) { + const [isTitleEditable, setIsTitleEditable] = useToggle(); + const [isBodyEditable, setIsBodyEditable] = useToggle(); + const inputRef = useRef(null); + const textareaRef = useRef(null); + + const isCover = () => page && page.id === 0; + const is404 = () => page && page.id === null; + + useEffect(() => { + inputRef.current && inputRef.current.focus(); + textareaRef.current && textareaRef.current.focus(); + }); + + const handleSubmit = (e) => { + e.preventDefault(); + }; + + const handleOnChange = (e) => { + let newValue = {}; + + switch (e.target.name) { + case "notebook-title": + newValue = { title: e.target.value }; + break; + case "notebook-body": + newValue = { body: e.target.value }; + break; + default: + break; + } + + setPage((previous) => { + return { ...previous, ...newValue }; + }); + }; + + return ( + <article + className={`notebook-page ${isCover() ? "notebook-page--cover" : ""}`} + > + <header className="notebook-page__header"> + {!isTitleEditable && ( + <h2 + className="notebook-page__title" + onClick={() => { + if (!is404()) setIsTitleEditable(); + }} + > + {page.title} + </h2> + )} + {isTitleEditable && ( + <form className="notebook-page__title" onSubmit={handleSubmit}> + <Input + ref={inputRef} + name="notebook-title" + value={page.title} + onChangeHandler={handleOnChange} + onBlurHandler={setIsTitleEditable} + /> + </form> + )} + </header> + {!isBodyEditable && ( + <div + className="notebook-page__content" + onClick={() => { + if (!is404()) setIsBodyEditable(); + }} + > + {page.body} + </div> + )} + {isBodyEditable && ( + <form className="notebook-page__content" onSubmit={handleSubmit}> + <TextArea + ref={textareaRef} + name="notebook-body" + value={page.body} + onChangeHandler={handleOnChange} + onBlurHandler={setIsBodyEditable} + /> + </form> + )} + <footer className="notebook-page__footer"> + {!isCover() && <div className="notebook-page__number">{page.id}</div>} + {!isCover() && ( + <PageToolbar + removePage={removePage} + restorePage={restorePage} + deletedPages={deletedPages} + /> + )} + </footer> + </article> + ); +} + +export default Page; diff --git a/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/PageToolbar.js b/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/PageToolbar.js new file mode 100644 index 0000000..a16aa22 --- /dev/null +++ b/public/projects/react-small-apps/apps/notebook/src/components/layout/Page/PageToolbar.js @@ -0,0 +1,27 @@ +import { Button } from "../../commons"; +import { ReactComponent as TrashIcon } from "../../../images/trash.svg"; +import { ReactComponent as RestoreIcon } from "../../../images/restore.svg"; + +function PageToolbar({ removePage, restorePage, deletedPages }) { + return ( + <div className="notebook-page__toolbar toolbar"> + <div className="toolbar__item"> + {deletedPages.length > 0 && ( + <Button modifier="restore" onClickHandler={restorePage}> + <RestoreIcon + title="Undo page deletion" + className="icon icon--restore" + /> + </Button> + )} + </div> + <div className="toolbar__item"> + <Button modifier="delete" onClickHandler={removePage}> + <TrashIcon title="Delete this page" className="icon icon--trash" /> + </Button> + </div> + </div> + ); +} + +export default PageToolbar; |
