├── .firebaserc ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── firebase.json ├── gifs ├── MenuComponent.gif ├── SideDrawer.gif └── highlight.gif ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.test.tsx ├── App.tsx ├── assets │ └── icons │ │ └── essentials │ │ ├── generateIndex.js │ │ ├── index.ts │ │ ├── svg │ │ ├── add.svg │ │ ├── at-circle.svg │ │ ├── bag.svg │ │ ├── bar-chart.svg │ │ ├── bookmarks.svg │ │ ├── chatbox-ellipses.svg │ │ ├── checkmark.svg │ │ ├── chevron-back.svg │ │ ├── chevron-forward.svg │ │ ├── close.svg │ │ ├── cloud-upload.svg │ │ ├── cloud.svg │ │ ├── color-fill.svg │ │ ├── color-palette.svg │ │ ├── color-wand.svg │ │ ├── dice.svg │ │ ├── document.svg │ │ ├── download.svg │ │ ├── ellipsis-horizontal.svg │ │ ├── ellipsis-vertical.svg │ │ ├── expand.svg │ │ ├── game-controller.svg │ │ ├── heart.svg │ │ ├── home.svg │ │ ├── link.svg │ │ ├── list.svg │ │ ├── log-out.svg │ │ ├── remove.svg │ │ ├── ribbon.svg │ │ ├── search.svg │ │ ├── settings.svg │ │ ├── share.svg │ │ ├── snow.svg │ │ ├── storefront.svg │ │ ├── tennisball.svg │ │ ├── text.svg │ │ ├── time.svg │ │ └── trophy.svg │ │ └── withStyle.tsx ├── components │ ├── Buttons │ │ ├── Button.tsx │ │ ├── IconButton.tsx │ │ └── index.ts │ ├── Hightlight │ │ ├── ColorGrid.tsx │ │ ├── Notes.tsx │ │ ├── StyleEditor.tsx │ │ ├── TextStyleGrid.tsx │ │ ├── index.tsx │ │ ├── styles.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── Menu │ │ ├── Container.tsx │ │ ├── Controls.tsx │ │ ├── Items.tsx │ │ ├── Menu.tsx │ │ ├── index.ts │ │ └── types.ts │ ├── SlideDrawer │ │ ├── Backdrop.tsx │ │ ├── SideDrawer.tsx │ │ ├── TogglerButton.tsx │ │ ├── content │ │ │ ├── Navs │ │ │ │ ├── Navitem.tsx │ │ │ │ ├── NavitemsGroup.tsx │ │ │ │ ├── Navs.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── sample_navs.tsx │ │ │ │ └── types.ts │ │ │ ├── Profile │ │ │ │ ├── Profile.tsx │ │ │ │ ├── index.ts │ │ │ │ └── sample_pic.jpg │ │ │ ├── QuickSettings.tsx │ │ │ └── SDContent.tsx │ │ ├── index.ts │ │ └── useSideDrawer.ts │ ├── Switch │ │ ├── Switch.tsx │ │ └── index.ts │ └── Tabs │ │ ├── index.tsx │ │ └── types.ts ├── configs │ └── themes.ts ├── containers │ ├── Home │ │ ├── Home.tsx │ │ ├── SampleHtml │ │ │ ├── base.css │ │ │ ├── default.css │ │ │ ├── index.tsx │ │ │ └── sample_html.ts │ │ └── sample_items.tsx │ └── TestComponent │ │ └── TestComponent.tsx ├── hooks │ ├── index.ts │ ├── useDimensions.ts │ ├── useHighlightRange.ts │ ├── usePosition.ts │ ├── useWindowResize.ts │ └── utils.ts ├── index.css ├── index.tsx ├── libs │ ├── highlight-range │ │ └── index.ts │ ├── pan │ │ ├── index.ts │ │ ├── pan.ts │ │ └── types.ts │ └── spring │ │ ├── index.ts │ │ ├── spring.ts │ │ └── types.ts ├── react-app-env.d.ts ├── reportWebVitals.ts ├── setupTests.ts └── types │ ├── css.d.ts │ └── react-style-object-to-css.d.ts ├── tsconfig.json └── yarn.lock /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "react-components-by-ruvkr" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | **/.directory 26 | /.firebase 27 | /.eslintcache -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A collection of Responsive Animated Mobile friendly Lightweight React Components 2 | 3 | - **100% Functional components** 4 | - **Modular** 5 | 6 | ## [👉 Live Demo 🌏](https://react-components-by-ruvkr.web.app/) 7 | 8 | ## Index 9 | 10 | - [Menu](#menu) 11 | - [Side Drawer](#side-drawer) 12 | - [Text Highlight](#text-highlight) 13 | 14 | ## Menu 15 | 16 | ![Menu](./gifs/MenuComponent.gif) 17 | 18 | - **Multi-level** 19 | - **Auto position** 20 | - **Auto-hide when clicked outside** 21 | - **Uses React portal** 22 | 23 | ## Side Drawer 24 | 25 | ![Side Drawer](./gifs/SideDrawer.gif) 26 | 27 | - **Swipeable** 28 | - **Responsive** 29 | - **Spring animated** 30 | 31 | ## Text Highlight 32 | 33 | ![Highlight](./gifs/highlight.gif) 34 | 35 | - **Highlight any range** 36 | - **Customize styles** 37 | - **Add note** 38 | 39 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /gifs/MenuComponent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruvkr/react-components-by-ruvkr/d8c00250eea7feb988619ab1c6f7ddd6927448ac/gifs/MenuComponent.gif -------------------------------------------------------------------------------- /gifs/SideDrawer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruvkr/react-components-by-ruvkr/d8c00250eea7feb988619ab1c6f7ddd6927448ac/gifs/SideDrawer.gif -------------------------------------------------------------------------------- /gifs/highlight.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruvkr/react-components-by-ruvkr/d8c00250eea7feb988619ab1c6f7ddd6927448ac/gifs/highlight.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-components-by-ruvkr", 3 | "version": "0.1.0", 4 | "private": false, 5 | "description": "", 6 | "author": { 7 | "name": "ruvkr", 8 | "email": "34903858+ruvkr@users.noreply.github.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git@github.com:ruvkr/react-components-by-ruvkr.git" 13 | }, 14 | "dependencies": { 15 | "@testing-library/jest-dom": "^5.11.4", 16 | "@testing-library/react": "^11.1.0", 17 | "@testing-library/user-event": "^12.1.10", 18 | "@types/jest": "^26.0.15", 19 | "@types/node": "^14.14.10", 20 | "@types/react": "^17.0.0", 21 | "@types/react-dom": "^17.0.0", 22 | "@types/styled-components": "^5.1.4", 23 | "@types/uuid": "^8.3.0", 24 | "csstype": "^3.0.6", 25 | "framer-motion": "^2.9.4", 26 | "polished": "^4.0.3", 27 | "react": "^17.0.1", 28 | "react-dom": "^17.0.1", 29 | "react-scripts": "4.0.1", 30 | "react-style-object-to-css": "^1.1.2", 31 | "style-to-js": "^1.1.0", 32 | "styled-components": "^5.2.1", 33 | "typescript": "^4.0.3", 34 | "uuid": "^8.3.1", 35 | "web-vitals": "^1.0.1" 36 | }, 37 | "scripts": { 38 | "start": "BROWSER=none react-scripts start", 39 | "build": "GENERATE_SOURCEMAP=false react-scripts build", 40 | "test": "react-scripts test", 41 | "eject": "react-scripts eject" 42 | }, 43 | "eslintConfig": { 44 | "extends": [ 45 | "react-app", 46 | "react-app/jest" 47 | ] 48 | }, 49 | "browserslist": { 50 | "production": [ 51 | ">0.2%", 52 | "not dead", 53 | "not op_mini all" 54 | ], 55 | "development": [ 56 | "last 1 chrome version", 57 | "last 1 firefox version", 58 | "last 1 safari version" 59 | ] 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruvkr/react-components-by-ruvkr/d8c00250eea7feb988619ab1c6f7ddd6927448ac/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruvkr/react-components-by-ruvkr/d8c00250eea7feb988619ab1c6f7ddd6927448ac/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruvkr/react-components-by-ruvkr/d8c00250eea7feb988619ab1c6f7ddd6927448ac/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react'; 2 | import styled from 'styled-components'; 3 | import { Home } from './containers/Home/Home'; 4 | import { SideDrawer } from './components/SlideDrawer'; 5 | 6 | export const App: React.FC = () => { 7 | const appRef = useRef(null); 8 | 9 | return ( 10 | 11 | 12 | 13 | 14 | ); 15 | }; 16 | 17 | const ScApp = styled.div` 18 | position: fixed; 19 | width: 100%; 20 | height: 100%; 21 | overflow: hidden; 22 | top: 0; 23 | right: 0; 24 | bottom: 0; 25 | left: 0; 26 | `; 27 | -------------------------------------------------------------------------------- /src/assets/icons/essentials/generateIndex.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const util = require('util'); 3 | const path = require('path'); 4 | 5 | const readDir = util.promisify(fs.readdir); 6 | const writeFile = util.promisify(fs.writeFile); 7 | 8 | const getSvgsInDir = dirPath => { 9 | return readDir(dirPath) 10 | .then(files => files.filter(file => /\.svg$/i.test(file))) 11 | .catch(console.log); 12 | }; 13 | 14 | const getNames = files => { 15 | return files.map(file => { 16 | const fileName = file 17 | .replace(/\.svg$/i, '') 18 | .replace(/[^A-Z0-9]/gi, ' ') 19 | .replace(/(^\w|\s\w)/g, m => m.toUpperCase()) 20 | .replace(/\s/g, ''); 21 | return { import: fileName + 'Svg', export: fileName, file: file }; 22 | }); 23 | }; 24 | 25 | const getModules = fileNames => { 26 | let importsString = 27 | "// This file is auto generated by generateIndex.js\n\nimport { withStyle } from './withStyle';\n\n"; 28 | let exportsString = '\n'; 29 | 30 | fileNames.forEach(name => { 31 | importsString += `import { ReactComponent as ${name.import} } from './svg/${name.file}';\n`; 32 | exportsString += `export const ${name.export} = withStyle(${name.import});\n`; 33 | }); 34 | 35 | return importsString + exportsString; 36 | }; 37 | 38 | const writeIndex = (path, strings) => { 39 | writeFile(path, strings, { encoding: 'utf-8' }) 40 | .then(_ => console.log('index.ts created!')) 41 | .catch(console.log); 42 | }; 43 | 44 | (async _ => { 45 | const svgsPath = path.join(__dirname, 'svg'); 46 | const indexPath = path.join(__dirname, 'index.ts'); 47 | const svgs = await getSvgsInDir(svgsPath); 48 | const fileNames = getNames(svgs); 49 | const strings = getModules(fileNames); 50 | await writeIndex(indexPath, strings); 51 | })(); 52 | -------------------------------------------------------------------------------- /src/assets/icons/essentials/index.ts: -------------------------------------------------------------------------------- 1 | // This file is auto generated by generateIndex.js 2 | 3 | import { withStyle } from './withStyle'; 4 | 5 | import { ReactComponent as AddSvg } from './svg/add.svg'; 6 | import { ReactComponent as AtCircleSvg } from './svg/at-circle.svg'; 7 | import { ReactComponent as BagSvg } from './svg/bag.svg'; 8 | import { ReactComponent as BarChartSvg } from './svg/bar-chart.svg'; 9 | import { ReactComponent as BookmarksSvg } from './svg/bookmarks.svg'; 10 | import { ReactComponent as ChatboxEllipsesSvg } from './svg/chatbox-ellipses.svg'; 11 | import { ReactComponent as CheckmarkSvg } from './svg/checkmark.svg'; 12 | import { ReactComponent as ChevronBackSvg } from './svg/chevron-back.svg'; 13 | import { ReactComponent as ChevronForwardSvg } from './svg/chevron-forward.svg'; 14 | import { ReactComponent as CloseSvg } from './svg/close.svg'; 15 | import { ReactComponent as CloudUploadSvg } from './svg/cloud-upload.svg'; 16 | import { ReactComponent as CloudSvg } from './svg/cloud.svg'; 17 | import { ReactComponent as ColorFillSvg } from './svg/color-fill.svg'; 18 | import { ReactComponent as ColorPaletteSvg } from './svg/color-palette.svg'; 19 | import { ReactComponent as ColorWandSvg } from './svg/color-wand.svg'; 20 | import { ReactComponent as DiceSvg } from './svg/dice.svg'; 21 | import { ReactComponent as DocumentSvg } from './svg/document.svg'; 22 | import { ReactComponent as DownloadSvg } from './svg/download.svg'; 23 | import { ReactComponent as EllipsisHorizontalSvg } from './svg/ellipsis-horizontal.svg'; 24 | import { ReactComponent as EllipsisVerticalSvg } from './svg/ellipsis-vertical.svg'; 25 | import { ReactComponent as ExpandSvg } from './svg/expand.svg'; 26 | import { ReactComponent as GameControllerSvg } from './svg/game-controller.svg'; 27 | import { ReactComponent as HeartSvg } from './svg/heart.svg'; 28 | import { ReactComponent as HomeSvg } from './svg/home.svg'; 29 | import { ReactComponent as LinkSvg } from './svg/link.svg'; 30 | import { ReactComponent as ListSvg } from './svg/list.svg'; 31 | import { ReactComponent as LogOutSvg } from './svg/log-out.svg'; 32 | import { ReactComponent as RemoveSvg } from './svg/remove.svg'; 33 | import { ReactComponent as RibbonSvg } from './svg/ribbon.svg'; 34 | import { ReactComponent as SearchSvg } from './svg/search.svg'; 35 | import { ReactComponent as SettingsSvg } from './svg/settings.svg'; 36 | import { ReactComponent as ShareSvg } from './svg/share.svg'; 37 | import { ReactComponent as SnowSvg } from './svg/snow.svg'; 38 | import { ReactComponent as StorefrontSvg } from './svg/storefront.svg'; 39 | import { ReactComponent as TennisballSvg } from './svg/tennisball.svg'; 40 | import { ReactComponent as TextSvg } from './svg/text.svg'; 41 | import { ReactComponent as TimeSvg } from './svg/time.svg'; 42 | import { ReactComponent as TrophySvg } from './svg/trophy.svg'; 43 | 44 | export const Add = withStyle(AddSvg); 45 | export const AtCircle = withStyle(AtCircleSvg); 46 | export const Bag = withStyle(BagSvg); 47 | export const BarChart = withStyle(BarChartSvg); 48 | export const Bookmarks = withStyle(BookmarksSvg); 49 | export const ChatboxEllipses = withStyle(ChatboxEllipsesSvg); 50 | export const Checkmark = withStyle(CheckmarkSvg); 51 | export const ChevronBack = withStyle(ChevronBackSvg); 52 | export const ChevronForward = withStyle(ChevronForwardSvg); 53 | export const Close = withStyle(CloseSvg); 54 | export const CloudUpload = withStyle(CloudUploadSvg); 55 | export const Cloud = withStyle(CloudSvg); 56 | export const ColorFill = withStyle(ColorFillSvg); 57 | export const ColorPalette = withStyle(ColorPaletteSvg); 58 | export const ColorWand = withStyle(ColorWandSvg); 59 | export const Dice = withStyle(DiceSvg); 60 | export const Document = withStyle(DocumentSvg); 61 | export const Download = withStyle(DownloadSvg); 62 | export const EllipsisHorizontal = withStyle(EllipsisHorizontalSvg); 63 | export const EllipsisVertical = withStyle(EllipsisVerticalSvg); 64 | export const Expand = withStyle(ExpandSvg); 65 | export const GameController = withStyle(GameControllerSvg); 66 | export const Heart = withStyle(HeartSvg); 67 | export const Home = withStyle(HomeSvg); 68 | export const Link = withStyle(LinkSvg); 69 | export const List = withStyle(ListSvg); 70 | export const LogOut = withStyle(LogOutSvg); 71 | export const Remove = withStyle(RemoveSvg); 72 | export const Ribbon = withStyle(RibbonSvg); 73 | export const Search = withStyle(SearchSvg); 74 | export const Settings = withStyle(SettingsSvg); 75 | export const Share = withStyle(ShareSvg); 76 | export const Snow = withStyle(SnowSvg); 77 | export const Storefront = withStyle(StorefrontSvg); 78 | export const Tennisball = withStyle(TennisballSvg); 79 | export const Text = withStyle(TextSvg); 80 | export const Time = withStyle(TimeSvg); 81 | export const Trophy = withStyle(TrophySvg); 82 | -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/add.svg: -------------------------------------------------------------------------------- 1 | Add -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/at-circle.svg: -------------------------------------------------------------------------------- 1 | At Circle -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/bag.svg: -------------------------------------------------------------------------------- 1 | Bag -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/bar-chart.svg: -------------------------------------------------------------------------------- 1 | Bar Chart -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/bookmarks.svg: -------------------------------------------------------------------------------- 1 | Bookmarks -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/chatbox-ellipses.svg: -------------------------------------------------------------------------------- 1 | Chatbox Ellipses -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/checkmark.svg: -------------------------------------------------------------------------------- 1 | Checkmark -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/chevron-back.svg: -------------------------------------------------------------------------------- 1 | Chevron Back -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/chevron-forward.svg: -------------------------------------------------------------------------------- 1 | Chevron Forward -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/close.svg: -------------------------------------------------------------------------------- 1 | Close -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/cloud-upload.svg: -------------------------------------------------------------------------------- 1 | Cloud Upload -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/cloud.svg: -------------------------------------------------------------------------------- 1 | Cloud -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/color-fill.svg: -------------------------------------------------------------------------------- 1 | Color Fill -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/color-palette.svg: -------------------------------------------------------------------------------- 1 | Color Palette -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/color-wand.svg: -------------------------------------------------------------------------------- 1 | Color Wand -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/dice.svg: -------------------------------------------------------------------------------- 1 | Dice -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/document.svg: -------------------------------------------------------------------------------- 1 | Document -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/download.svg: -------------------------------------------------------------------------------- 1 | Download -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/ellipsis-horizontal.svg: -------------------------------------------------------------------------------- 1 | Ellipsis Horizontal -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/ellipsis-vertical.svg: -------------------------------------------------------------------------------- 1 | Ellipsis Vertical -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/expand.svg: -------------------------------------------------------------------------------- 1 | Expand -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/game-controller.svg: -------------------------------------------------------------------------------- 1 | Game Controller -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/heart.svg: -------------------------------------------------------------------------------- 1 | Heart -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/home.svg: -------------------------------------------------------------------------------- 1 | Home -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/link.svg: -------------------------------------------------------------------------------- 1 | Link -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/list.svg: -------------------------------------------------------------------------------- 1 | List -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/log-out.svg: -------------------------------------------------------------------------------- 1 | Log Out -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/remove.svg: -------------------------------------------------------------------------------- 1 | Remove -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/ribbon.svg: -------------------------------------------------------------------------------- 1 | Ribbon -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/search.svg: -------------------------------------------------------------------------------- 1 | Search -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/settings.svg: -------------------------------------------------------------------------------- 1 | Settings -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/share.svg: -------------------------------------------------------------------------------- 1 | Share -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/snow.svg: -------------------------------------------------------------------------------- 1 | Snow -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/storefront.svg: -------------------------------------------------------------------------------- 1 | Storefront -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/tennisball.svg: -------------------------------------------------------------------------------- 1 | Tennisball -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/text.svg: -------------------------------------------------------------------------------- 1 | Text -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/time.svg: -------------------------------------------------------------------------------- 1 | Time -------------------------------------------------------------------------------- /src/assets/icons/essentials/svg/trophy.svg: -------------------------------------------------------------------------------- 1 | Trophy -------------------------------------------------------------------------------- /src/assets/icons/essentials/withStyle.tsx: -------------------------------------------------------------------------------- 1 | export const withStyle = ( 2 | SVG: React.FC>, 3 | ): React.FC => { 4 | return props => { 5 | return ( 6 | 13 | ); 14 | }; 15 | }; 16 | 17 | export default withStyle; 18 | -------------------------------------------------------------------------------- /src/components/Buttons/Button.tsx: -------------------------------------------------------------------------------- 1 | import { rgba } from 'polished'; 2 | import styled from 'styled-components'; 3 | 4 | interface Props { 5 | disabled?: boolean; 6 | icon?: JSX.Element; 7 | name?: string; 8 | className?: string; 9 | onClick?: (event: React.MouseEvent) => void; 10 | } 11 | 12 | export const Button: React.FC = ({ 13 | disabled = false, 14 | icon, 15 | name, 16 | className, 17 | onClick, 18 | }) => { 19 | return ( 20 | 21 | 22 | {icon && {icon}} 23 | {name && {name}} 24 | 25 | 26 | ); 27 | }; 28 | 29 | const ScButton = styled.button` 30 | font: inherit; 31 | padding: 0; 32 | margin: 0; 33 | border: none; 34 | display: flex; 35 | background-color: transparent; 36 | cursor: pointer; 37 | transition: opacity 300ms ease-in-out; 38 | 39 | &:focus, 40 | &:active { 41 | outline: none; 42 | & > div { 43 | box-shadow: 0 0 0 2px ${p => p.theme.col3}; 44 | transition: box-shadow 300ms ease-in-out; 45 | } 46 | } 47 | &:disabled { 48 | cursor: not-allowed; 49 | opacity: 0.2; 50 | transition: opacity 300ms ease-in-out; 51 | } 52 | 53 | @media (hover: hover) and (pointer: fine) { 54 | &:hover:not(:disabled) { 55 | & > div { 56 | box-shadow: 0 0 0 2px ${p => p.theme.col3}; 57 | transition: box-shadow 300ms ease-in-out; 58 | } 59 | } 60 | } 61 | `; 62 | 63 | const ScFocus = styled.div` 64 | width: 100%; 65 | height: 100%; 66 | min-height: 36px; 67 | display: flex; 68 | align-items: center; 69 | border-radius: 999px; 70 | background-color: ${p => p.theme.col4}; 71 | overflow: hidden; 72 | transition: box-shadow 300ms ease-in-out; 73 | 74 | &:focus, 75 | &:active { 76 | outline: none; 77 | } 78 | `; 79 | 80 | const ScIcon = styled.div` 81 | display: flex; 82 | flex-shrink: 0; 83 | width: 36px; 84 | height: 36px; 85 | padding: 8px; 86 | color: ${p => p.theme.col2}; 87 | fill: ${p => p.theme.col2}; 88 | stroke: ${p => p.theme.col2}; 89 | background-color: rgba(0, 0, 0, 0.15); 90 | `; 91 | 92 | const ScLabel = styled.div<{ $hasIcon: boolean }>` 93 | color: ${p => rgba(p.theme.col1, 0.5)}; 94 | padding: 8px 16px; 95 | padding-left: ${p => (p.$hasIcon ? 8 : 16)}px; 96 | `; 97 | -------------------------------------------------------------------------------- /src/components/Buttons/IconButton.tsx: -------------------------------------------------------------------------------- 1 | import styled, { css } from 'styled-components'; 2 | 3 | interface Props { 4 | disabled?: boolean; 5 | active?: boolean; 6 | icon: JSX.Element; 7 | className?: string; 8 | onClick?: (event: React.MouseEvent) => void; 9 | } 10 | 11 | export const IconButton: React.FC = ({ 12 | disabled = false, 13 | active = false, 14 | icon, 15 | className, 16 | onClick, 17 | }) => { 18 | return ( 19 | 20 | 21 | {icon} 22 | 23 | 24 | ); 25 | }; 26 | 27 | const ScButton = styled.button` 28 | font: inherit; 29 | padding: 0; 30 | margin: 0; 31 | border: none; 32 | display: flex; 33 | background-color: transparent; 34 | cursor: pointer; 35 | transition: opacity 300ms ease-in-out; 36 | 37 | &:focus, 38 | &:active { 39 | outline: none; 40 | & > div { 41 | box-shadow: 0 0 0 2px ${p => p.theme.col3}; 42 | transition: box-shadow 300ms ease-in-out; 43 | } 44 | } 45 | &:disabled { 46 | cursor: not-allowed; 47 | opacity: 0.2; 48 | transition: opacity 300ms ease-in-out; 49 | } 50 | 51 | @media (hover: hover) and (pointer: fine) { 52 | &:hover:not(:disabled) { 53 | & > div { 54 | box-shadow: 0 0 0 2px ${p => p.theme.col3}; 55 | transition: box-shadow 300ms ease-in-out; 56 | } 57 | } 58 | } 59 | `; 60 | 61 | const ScFocus = styled.div<{ $active: boolean }>( 62 | ({ $active, theme }) => css` 63 | width: 36px; 64 | height: 36px; 65 | border-radius: 50%; 66 | overflow: hidden; 67 | background-color: ${$active ? theme.col2 : theme.col4}; 68 | transition: all 300ms ease-in-out; 69 | 70 | &:focus, 71 | &:active { 72 | outline: none; 73 | } 74 | ` 75 | ); 76 | 77 | const ScIcon = styled.div<{ $active: boolean }>( 78 | ({ $active, theme }) => css` 79 | display: flex; 80 | flex-shrink: 0; 81 | width: 36px; 82 | height: 36px; 83 | padding: 8px; 84 | color: ${$active ? theme.col4 : theme.col2}; 85 | fill: ${$active ? theme.col4 : theme.col2}; 86 | stroke: ${$active ? theme.col4 : theme.col2}; 87 | transition: all 300ms ease-in-out; 88 | ` 89 | ); 90 | -------------------------------------------------------------------------------- /src/components/Buttons/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Button'; 2 | export * from './IconButton'; 3 | -------------------------------------------------------------------------------- /src/components/Hightlight/ColorGrid.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { rgba } from 'polished'; 3 | import { Close } from '../../assets/icons/essentials'; 4 | 5 | interface Props { 6 | name: string; 7 | colors: string[]; 8 | activeColor?: string; 9 | onChange?: (color: string) => void; 10 | } 11 | 12 | export const ColorGrid: React.FC = ({ 13 | name, 14 | colors, 15 | activeColor, 16 | onChange, 17 | }) => { 18 | const _colors = colors.map(color => ( 19 | onChange && onChange(color)}> 20 | 21 | 22 | )); 23 | 24 | return ( 25 | 26 | 27 | 28 | onChange && onChange('inherit')} 31 | children={ 32 | } 36 | /> 37 | } 38 | /> 39 | {_colors} 40 | 41 | 42 | ); 43 | }; 44 | 45 | const ScContainer = styled.div` 46 | display: grid; 47 | grid-auto-flow: row; 48 | grid-auto-rows: min-content; 49 | grid-gap: 8px; 50 | `; 51 | 52 | const ScLabel = styled.label` 53 | width: 100%; 54 | padding: 0; 55 | margin: 0; 56 | color: ${p => rgba(p.theme.col1, 0.5)}; 57 | `; 58 | 59 | const ScColorGrid = styled.div` 60 | width: 100%; 61 | display: flex; 62 | flex-wrap: wrap; 63 | `; 64 | 65 | const ScColorItem = styled.button` 66 | font: inherit; 67 | padding: 0; 68 | margin: 2px; 69 | border: none; 70 | background-color: transparent; 71 | cursor: pointer; 72 | 73 | &:focus, 74 | &:active { 75 | outline: none; 76 | & > div { 77 | transform: scale(1.1); 78 | transition: transform 300ms ease-in-out; 79 | } 80 | } 81 | 82 | @media (hover: hover) and (pointer: fine) { 83 | &:hover:not(:disabled) { 84 | & > div { 85 | transform: scale(1.1); 86 | transition: transform 300ms ease-in-out; 87 | } 88 | } 89 | } 90 | `; 91 | 92 | const ScFocus = styled.div<{ $color: string; $active: boolean }>` 93 | width: 28px; 94 | height: 28px; 95 | background-color: ${p => p.$color}; 96 | border-radius: ${p => (p.$active ? 50 : 0)}%; 97 | transition: transform 300ms ease-in-out; 98 | 99 | &:focus, 100 | &:active { 101 | outline: none; 102 | } 103 | `; 104 | 105 | const ScNoneFocus = styled.div<{ $active: boolean }>` 106 | width: 28px; 107 | height: 28px; 108 | padding: 6px; 109 | background-color: ${p => p.theme.col4}; 110 | border-radius: ${p => (p.$active ? 50 : 0)}%; 111 | transition: transform 300ms ease-in-out; 112 | 113 | &:focus, 114 | &:active { 115 | outline: none; 116 | } 117 | `; 118 | 119 | const ScNoneIcon = styled(Close)` 120 | width: 100%; 121 | height: 100%; 122 | display: flex; 123 | color: ${p => p.theme.col2}; 124 | fill: ${p => p.theme.col2}; 125 | stroke: ${p => p.theme.col2}; 126 | `; 127 | -------------------------------------------------------------------------------- /src/components/Hightlight/Notes.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import styled, { css } from 'styled-components'; 3 | import { rgba } from 'polished'; 4 | import { Button } from '../Buttons'; 5 | import { Checkmark, Remove } from '../../assets/icons/essentials'; 6 | 7 | interface Props { 8 | note: string | null; 9 | updateNote: (note: string) => void; 10 | } 11 | 12 | export const Notes: React.FC = ({ note, updateNote }) => { 13 | const [value, setValue] = useState(note ?? ''); 14 | 15 | const changeHandler = (event: React.ChangeEvent) => { 16 | const target = event.target as HTMLTextAreaElement; 17 | target.style.height = ''; 18 | target.style.height = Math.min(target.scrollHeight, 240) + 'px'; 19 | const value = target.value; 20 | setValue(value); 21 | }; 22 | 23 | const removeHandler = () => { 24 | setValue(''); 25 | updateNote(''); 26 | }; 27 | 28 | return ( 29 | 30 | 36 | 37 |