From 876d575854c34ee85253ce2d347f7ef7b32d85e9 Mon Sep 17 00:00:00 2001 From: MAZE Date: Sat, 31 Aug 2024 14:45:10 +0330 Subject: [PATCH] feat: add toolbox --- src/components/menu/items/index.ts | 2 + src/components/menu/items/notepad.tsx | 23 +++ src/components/menu/items/pomodoro.tsx | 23 +++ src/components/menu/menu.tsx | 15 ++ .../toolbox/generics/button/button.module.css | 34 ++++ .../toolbox/generics/button/button.tsx | 33 ++++ .../toolbox/generics/button/index.ts | 1 + src/components/toolbox/index.ts | 2 + .../toolbox/notepad/button/button.module.css | 45 +++++ .../toolbox/notepad/button/button.tsx | 36 ++++ .../toolbox/notepad/button/index.ts | 1 + src/components/toolbox/notepad/index.ts | 1 + .../toolbox/notepad/notepad.module.css | 44 +++++ src/components/toolbox/notepad/notepad.tsx | 90 +++++++++ src/components/toolbox/pomodoro/index.ts | 1 + .../toolbox/pomodoro/pomodoro.module.css | 36 ++++ src/components/toolbox/pomodoro/pomodoro.tsx | 179 ++++++++++++++++++ .../toolbox/pomodoro/setting/index.ts | 1 + .../pomodoro/setting/setting.module.css | 76 ++++++++ .../toolbox/pomodoro/setting/setting.tsx | 110 +++++++++++ src/components/toolbox/pomodoro/tabs/index.ts | 1 + .../toolbox/pomodoro/tabs/tabs.module.css | 43 +++++ src/components/toolbox/pomodoro/tabs/tabs.tsx | 25 +++ 23 files changed, 822 insertions(+) create mode 100644 src/components/menu/items/notepad.tsx create mode 100644 src/components/menu/items/pomodoro.tsx create mode 100644 src/components/toolbox/generics/button/button.module.css create mode 100644 src/components/toolbox/generics/button/button.tsx create mode 100644 src/components/toolbox/generics/button/index.ts create mode 100644 src/components/toolbox/index.ts create mode 100644 src/components/toolbox/notepad/button/button.module.css create mode 100644 src/components/toolbox/notepad/button/button.tsx create mode 100644 src/components/toolbox/notepad/button/index.ts create mode 100644 src/components/toolbox/notepad/index.ts create mode 100644 src/components/toolbox/notepad/notepad.module.css create mode 100644 src/components/toolbox/notepad/notepad.tsx create mode 100644 src/components/toolbox/pomodoro/index.ts create mode 100644 src/components/toolbox/pomodoro/pomodoro.module.css create mode 100644 src/components/toolbox/pomodoro/pomodoro.tsx create mode 100644 src/components/toolbox/pomodoro/setting/index.ts create mode 100644 src/components/toolbox/pomodoro/setting/setting.module.css create mode 100644 src/components/toolbox/pomodoro/setting/setting.tsx create mode 100644 src/components/toolbox/pomodoro/tabs/index.ts create mode 100644 src/components/toolbox/pomodoro/tabs/tabs.module.css create mode 100644 src/components/toolbox/pomodoro/tabs/tabs.tsx diff --git a/src/components/menu/items/index.ts b/src/components/menu/items/index.ts index 3767bbe..a74fae8 100644 --- a/src/components/menu/items/index.ts +++ b/src/components/menu/items/index.ts @@ -6,3 +6,5 @@ export { Presets as PresetsItem } from './presets'; export { Shortcuts as ShortcutsItem } from './shortcuts'; export { SleepTimer as SleepTimerItem } from './sleep-timer'; export { BreathingExercise as BreathingExerciseItem } from './breathing-exercise'; +export { Pomodoro as PomodoroItem } from './pomodoro'; +export { Notepad as NotepadItem } from './notepad'; diff --git a/src/components/menu/items/notepad.tsx b/src/components/menu/items/notepad.tsx new file mode 100644 index 0000000..ef0ff39 --- /dev/null +++ b/src/components/menu/items/notepad.tsx @@ -0,0 +1,23 @@ +import { MdNotes } from 'react-icons/md/index'; + +import { Item } from '../item'; + +import { useNoteStore } from '@/stores/note'; + +interface NotepadProps { + open: () => void; +} + +export function Notepad({ open }: NotepadProps) { + const note = useNoteStore(state => state.note); + + return ( + } + label="Notepad" + shortcut="Shift + N" + onClick={open} + /> + ); +} diff --git a/src/components/menu/items/pomodoro.tsx b/src/components/menu/items/pomodoro.tsx new file mode 100644 index 0000000..43473b5 --- /dev/null +++ b/src/components/menu/items/pomodoro.tsx @@ -0,0 +1,23 @@ +import { MdOutlineAvTimer } from 'react-icons/md/index'; + +import { Item } from '../item'; + +import { usePomodoroStore } from '@/stores/pomodoro'; + +interface PomodoroProps { + open: () => void; +} + +export function Pomodoro({ open }: PomodoroProps) { + const running = usePomodoroStore(state => state.running); + + return ( + } + label="Pomodoro" + shortcut="Shift + P" + onClick={open} + /> + ); +} diff --git a/src/components/menu/menu.tsx b/src/components/menu/menu.tsx index 2ee9da7..69e44f9 100644 --- a/src/components/menu/menu.tsx +++ b/src/components/menu/menu.tsx @@ -13,6 +13,8 @@ import { ShortcutsItem, SleepTimerItem, BreathingExerciseItem, + PomodoroItem, + NotepadItem, } from './items'; import { Divider } from './divider'; import { ShareLinkModal } from '@/components/modals/share-link'; @@ -20,6 +22,7 @@ import { PresetsModal } from '@/components/modals/presets'; import { ShortcutsModal } from '@/components/modals/shortcuts'; import { SleepTimerModal } from '@/components/modals/sleep-timer'; import { BreathingExerciseModal } from '../modals/breathing'; +import { Pomodoro, Notepad } from '../toolbox'; import { fade, mix, slideY } from '@/lib/motion'; import { useSoundStore } from '@/stores/sound'; @@ -35,6 +38,8 @@ export function Menu() { const initial = useMemo( () => ({ breathing: false, + notepad: false, + pomodoro: false, presets: false, shareLink: false, shortcuts: false, @@ -103,7 +108,11 @@ export function Menu() { open('shareLink')} /> open('sleepTimer')} /> + + open('breathing')} /> + open('pomodoro')} /> + open('notepad')} /> open('shortcuts')} /> @@ -131,6 +140,12 @@ export function Menu() { show={modals.shortcuts} onClose={() => close('shortcuts')} /> + open('pomodoro')} + show={modals.pomodoro} + onClose={() => close('pomodoro')} + /> + close('notepad')} /> close('presets')} /> void; + smallIcon?: boolean; + tooltip: string; +} + +export function Button({ + disabled = false, + icon, + onClick, + smallIcon, + tooltip, +}: ButtonProps) { + return ( + + + + ); +} diff --git a/src/components/toolbox/generics/button/index.ts b/src/components/toolbox/generics/button/index.ts new file mode 100644 index 0000000..a039b75 --- /dev/null +++ b/src/components/toolbox/generics/button/index.ts @@ -0,0 +1 @@ +export { Button } from './button'; diff --git a/src/components/toolbox/index.ts b/src/components/toolbox/index.ts new file mode 100644 index 0000000..b4b226a --- /dev/null +++ b/src/components/toolbox/index.ts @@ -0,0 +1,2 @@ +export { Notepad } from './notepad'; +export { Pomodoro } from './pomodoro'; diff --git a/src/components/toolbox/notepad/button/button.module.css b/src/components/toolbox/notepad/button/button.module.css new file mode 100644 index 0000000..4a4e756 --- /dev/null +++ b/src/components/toolbox/notepad/button/button.module.css @@ -0,0 +1,45 @@ +.button { + display: flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; + font-size: var(--font-sm); + color: var(--color-foreground); + cursor: pointer; + background-color: var(--color-neutral-100); + border: 1px solid var(--color-neutral-200); + border-radius: 4px; + outline: none; + transition: 0.2s; + transition-property: border-color, color, background-color; + + &:focus-visible { + outline: 2px solid var(--color-neutral-400); + outline-offset: 2px; + } + + &.critical { + color: #f43f5e; + border-color: #f43f5e; + + &:hover { + background-color: rgb(244 63 94 / 10%); + } + } + + &.recommended { + font-size: var(--font-xsm); + color: #22c55e; + border-color: #22c55e; + + &:hover { + background-color: rgb(34 197 94 / 10%); + } + } + + &:hover, + &:focus-visible { + background-color: var(--color-neutral-200); + } +} diff --git a/src/components/toolbox/notepad/button/button.tsx b/src/components/toolbox/notepad/button/button.tsx new file mode 100644 index 0000000..d3da910 --- /dev/null +++ b/src/components/toolbox/notepad/button/button.tsx @@ -0,0 +1,36 @@ +import { Tooltip } from '@/components/tooltip'; + +import { cn } from '@/helpers/styles'; + +import styles from './button.module.css'; + +interface ButtonProps { + critical?: boolean; + icon: React.ReactElement; + onClick: () => void; + recommended?: boolean; + tooltip: string; +} + +export function Button({ + critical, + icon, + onClick, + recommended, + tooltip, +}: ButtonProps) { + return ( + + + + ); +} diff --git a/src/components/toolbox/notepad/button/index.ts b/src/components/toolbox/notepad/button/index.ts new file mode 100644 index 0000000..a039b75 --- /dev/null +++ b/src/components/toolbox/notepad/button/index.ts @@ -0,0 +1 @@ +export { Button } from './button'; diff --git a/src/components/toolbox/notepad/index.ts b/src/components/toolbox/notepad/index.ts new file mode 100644 index 0000000..8a3fad5 --- /dev/null +++ b/src/components/toolbox/notepad/index.ts @@ -0,0 +1 @@ +export { Notepad } from './notepad'; diff --git a/src/components/toolbox/notepad/notepad.module.css b/src/components/toolbox/notepad/notepad.module.css new file mode 100644 index 0000000..2dadc40 --- /dev/null +++ b/src/components/toolbox/notepad/notepad.module.css @@ -0,0 +1,44 @@ +.header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 8px; + + & .label { + font-size: var(--font-sm); + font-weight: 500; + color: var(--color-foreground-subtle); + } + + & .buttons { + display: flex; + column-gap: 4px; + align-items: center; + } +} + +.textarea { + width: 100%; + height: 350px; + padding: 12px; + line-height: 1.6; + color: var(--color-foreground-subtle); + resize: none; + background-color: var(--color-neutral-50); + border: 1px solid var(--color-neutral-200); + border-radius: 4px; + outline: none; + scroll-padding-bottom: 12px; + + &:focus-visible { + outline: 2px solid var(--color-neutral-400); + outline-offset: 2px; + } +} + +.counter { + margin-top: 8px; + font-size: var(--font-xsm); + color: var(--color-foreground-subtle); + text-align: center; +} diff --git a/src/components/toolbox/notepad/notepad.tsx b/src/components/toolbox/notepad/notepad.tsx new file mode 100644 index 0000000..921556f --- /dev/null +++ b/src/components/toolbox/notepad/notepad.tsx @@ -0,0 +1,90 @@ +import { useRef, useEffect } from 'react'; +import { BiTrash } from 'react-icons/bi/index'; +import { LuCopy, LuDownload } from 'react-icons/lu/index'; +import { FaCheck } from 'react-icons/fa6/index'; +import { FaUndo } from 'react-icons/fa/index'; + +import { Modal } from '@/components/modal'; +import { Button } from './button'; + +import { useNoteStore } from '@/stores/note'; +import { useCopy } from '@/hooks/use-copy'; +import { download } from '@/helpers/download'; + +import styles from './notepad.module.css'; + +interface NotepadProps { + onClose: () => void; + show: boolean; +} + +export function Notepad({ onClose, show }: NotepadProps) { + const textareaRef = useRef(null); + + const note = useNoteStore(state => state.note); + const history = useNoteStore(state => state.history); + const write = useNoteStore(state => state.write); + const words = useNoteStore(state => state.words()); + const characters = useNoteStore(state => state.characters()); + const clear = useNoteStore(state => state.clear); + const restore = useNoteStore(state => state.restore); + + const { copy, copying } = useCopy(); + + useEffect(() => { + if (show && textareaRef.current) { + setTimeout(() => { + textareaRef.current?.focus(); + }, 10); + } + }, [show]); + + const handleKeyDown = (e: React.KeyboardEvent) => { + e.stopPropagation(); + + if (e.key === 'Escape') onClose(); + }; + + return ( + +
+

Your Note

+
+
+
+ +