From f2ecc1803f3ea294a0c6b7915b61348ed0395b26 Mon Sep 17 00:00:00 2001 From: Marcin Zelent Date: Wed, 16 Nov 2022 15:16:38 +0100 Subject: Remade and extended the app using React --- src/components/Sidebar/Sidebar.module.css | 158 ++++++++++++++++++++++++++++++ src/components/Sidebar/Sidebar.tsx | 152 ++++++++++++++++++++++++++++ 2 files changed, 310 insertions(+) create mode 100644 src/components/Sidebar/Sidebar.module.css create mode 100644 src/components/Sidebar/Sidebar.tsx (limited to 'src/components/Sidebar') diff --git a/src/components/Sidebar/Sidebar.module.css b/src/components/Sidebar/Sidebar.module.css new file mode 100644 index 0000000..8081492 --- /dev/null +++ b/src/components/Sidebar/Sidebar.module.css @@ -0,0 +1,158 @@ +.aside { + min-width: 272px; + width: 20%; + height: 100%; + padding: 5px; + display: flex; + flex-direction: column; + border-right: 1px solid #e5e5e5; + box-shadow: -2px 0 10px #000; + z-index: 9999; + background-color: #fff; +} + +.headline { + padding-left: 16px; + position: relative; +} + +.headline h2 { + display: inline-block; + line-height: 40px; + margin-bottom: 0; +} + +.headline button { + width: 40px; + height: 40px; + padding: 0; + margin-left: 2px; + display: inline-block; + border: none; + border-radius: 100%; + background: none; + cursor: pointer; +} + +.headline button:hover { + background: #e9f3ff; +} + +.headline button div { + width: 8px; + height: 8px; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #000; + display: inline-block; +} + +.tripList { + min-width: 80%; + padding: 5px 0; + position: absolute; + top: 100%; + left: 16px; + background: #fff; + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 5px; + box-shadow: 0 12px 28px 0 rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1); +} + +.tripList ul { + margin: 0; + padding: 0; + list-style-type: none; +} + +.tripList li { + padding: 5px; + user-select: none; +} + +.tripList li a { + padding: 10px 20px 10px 10px; + display: block; + border-radius: 5px; + font-weight: bold; + cursor: pointer; +} + +.tripList li a:hover { + background-color: #f5f5f5; +} + +.list { + margin: 24px 0 0 0; + padding: 0; + list-style: none; + overflow-y: auto; +} + +.listItem { + min-height: 56px; + margin-bottom: 5px; + padding: 10px 16px; + display: flex; + border-radius: 10px; + cursor: pointer; + user-select: none; + outline: currentcolor none medium; +} + +.listItem:hover { + background-color: #f5f5f5; +} + +.listItem:hover > .listItemButton{ + display: flex; +} + +.listItemActive { + background-color: #e9f3ff !important; +} + +.listItemContent { + max-width: calc(100% - 36px); + margin: auto 0; + flex-grow: 1; +} + +.listItemButton { + width: 36px; + height: 36px; + padding: 9px; + margin: auto; + display: none; + border: none; + border-radius: 36px; + box-shadow: 0 0 0 1px rgb(0 0 0 / 10%); + background: #fff; + cursor: pointer; +} + +.listItemButton:hover { + background: #fafafa; +} + +.listItemButton svg { + margin: auto; +} + +.preformatted { + white-space: pre; +} + +@media only screen and (max-width: 500px) { + .aside { + position: absolute; + top: 0; + bottom: 0; + left: -100vw; + transition: left 0.3s ease-in; + } + + .asideOpen { + left: 0; + } +} diff --git a/src/components/Sidebar/Sidebar.tsx b/src/components/Sidebar/Sidebar.tsx new file mode 100644 index 0000000..b4ddaa9 --- /dev/null +++ b/src/components/Sidebar/Sidebar.tsx @@ -0,0 +1,152 @@ +import React, { useEffect, useRef, useState } from 'react'; + +import { Group, Trip } from '../../models'; + +import styles from './Sidebar.module.css'; + +interface Props { + trips: Trip[]; + currentTrip: Trip; + groups: Group[]; + currentGroup: Group | undefined; + headline?: string; + asideOpen: boolean; + handleClose: () => void; + handleGroupChange: (groupIndex: number, openGallery?: boolean) => void; + handleTripChange: (tripIndex: number) => void; +} + +export default function Sidebar({ + trips, + currentTrip, + groups, + currentGroup, + asideOpen, + handleClose, + handleGroupChange, + handleTripChange, +}: Props): JSX.Element { + const [tripListOpen, setTripListOpen] = useState(false); + const wrapperRef = useRef(null); + + useEffect(() => { + function handleClickOutside(e: Event): void { + if ( + wrapperRef.current !== null && + e.target !== null && + !wrapperRef.current.contains(e.target as Node) + ) { + handleClose(); + } + } + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [wrapperRef]); + + function groupChangeHandler(groupIndex: number, openGallery?: boolean): void { + handleGroupChange(groupIndex, openGallery); + handleClose(); + } + + function tripChangeHandler(tripIndex: number): void { + handleTripChange(tripIndex); + setTripListOpen(false); + } + + function buildGroupDescription( + template: string | undefined, + tokens: { [key: string]: string | number } | undefined, + ): string { + if (template === undefined) { + return ''; + } + + let description = template; + + if (tokens === undefined) { + return description; + } + + Object.keys(tokens).forEach((key) => { + description = description.replaceAll(`{${key}}`, `${tokens[key]}`); + }); + + return description; + } + + const asideStyle = asideOpen ? `${styles.aside} ${styles.asideOpen}` : styles.aside; + + return ( + + ); +} -- cgit v1.2.3