diff --git a/app/assets/icons/ic-copy.svg b/app/assets/icons/ic-copy.svg new file mode 100644 index 000000000..9ad40e8f1 --- /dev/null +++ b/app/assets/icons/ic-copy.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/icons/ic-download.svg b/app/assets/icons/ic-download.svg new file mode 100644 index 000000000..de2c70fc2 --- /dev/null +++ b/app/assets/icons/ic-download.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/javascripts/app.ts b/app/assets/javascripts/app.ts index e7470bbe0..b493808ad 100644 --- a/app/assets/javascripts/app.ts +++ b/app/assets/javascripts/app.ts @@ -65,7 +65,7 @@ import { NotesContextMenuDirective } from './components/NotesContextMenu'; import { NotesOptionsPanelDirective } from './components/NotesOptionsPanel'; import { IconDirective } from './components/Icon'; import { NoteTagsContainerDirective } from './components/NoteTagsContainer'; -import { PreferencesDirective } from './components/preferences'; +import { PreferencesDirective } from './preferences'; function reloadHiddenFirefoxTab(): boolean { /** diff --git a/app/assets/javascripts/components/DecoratedInput.tsx b/app/assets/javascripts/components/DecoratedInput.tsx new file mode 100644 index 000000000..860b6b362 --- /dev/null +++ b/app/assets/javascripts/components/DecoratedInput.tsx @@ -0,0 +1,42 @@ +import { FunctionalComponent, ComponentChild } from 'preact'; + +interface Props { + className?: string; + disabled?: boolean; + left?: ComponentChild[]; + right?: ComponentChild[]; + text?: string; +} + +/** + * Input that can be decorated on the left and right side + */ +export const DecoratedInput: FunctionalComponent = ({ + className = '', + disabled = false, + left, + right, + text, +}) => { + const base = + 'rounded py-1.5 px-3 text-input my-1 h-8 flex flex-row items-center gap-4'; + const stateClasses = disabled + ? 'no-border bg-grey-5' + : 'border-solid border-1 border-gray-300'; + const classes = `${base} ${stateClasses} ${className}`; + + return ( +
+ {left} +
+ +
+ {right} +
+ ); +}; diff --git a/app/assets/javascripts/components/Icon.tsx b/app/assets/javascripts/components/Icon.tsx index e9c9a8b1e..c6f9f632c 100644 --- a/app/assets/javascripts/components/Icon.tsx +++ b/app/assets/javascripts/components/Icon.tsx @@ -23,6 +23,8 @@ import SettingsIcon from '../../icons/ic-settings.svg'; import StarIcon from '../../icons/ic-star.svg'; import ThemesIcon from '../../icons/ic-themes.svg'; import UserIcon from '../../icons/ic-user.svg'; +import CopyIcon from '../../icons/ic-copy.svg'; +import DownloadIcon from '../../icons/ic-download.svg'; import { toDirective } from './utils'; import { FunctionalComponent } from 'preact'; @@ -52,6 +54,8 @@ const ICONS = { star: StarIcon, themes: ThemesIcon, user: UserIcon, + copy: CopyIcon, + download: DownloadIcon, }; export type IconType = keyof typeof ICONS; @@ -61,7 +65,7 @@ type Props = { className?: string; }; -export const Icon: FunctionalComponent = ({ type, className }) => { +export const Icon: FunctionalComponent = ({ type, className = '' }) => { const IconComponent = ICONS[type]; return ; }; diff --git a/app/assets/javascripts/components/IconButton.tsx b/app/assets/javascripts/components/IconButton.tsx index 93d826c4e..8c0920c64 100644 --- a/app/assets/javascripts/components/IconButton.tsx +++ b/app/assets/javascripts/components/IconButton.tsx @@ -1,53 +1,38 @@ import { FunctionComponent } from 'preact'; import { Icon, IconType } from './Icon'; -const ICON_BUTTON_TYPES: { - [type: string]: { className: string }; -} = { - normal: { - className: '', - }, - primary: { - className: 'info', - }, -}; - -export type IconButtonType = keyof typeof ICON_BUTTON_TYPES; - -interface IconButtonProps { +interface Props { /** * onClick - preventDefault is handled within the component */ onClick: () => void; - type: IconButtonType; - className?: string; - iconType: IconType; + icon: IconType; } /** - * CircleButton component with an icon for SPA + * IconButton component with an icon * preventDefault is already handled within the component */ -export const IconButton: FunctionComponent = ({ +export const IconButton: FunctionComponent = ({ onClick, - type, className, - iconType, + icon, }) => { const click = (e: MouseEvent) => { e.preventDefault(); onClick(); }; - const typeProps = ICON_BUTTON_TYPES[type]; return ( ); }; diff --git a/app/assets/javascripts/components/Input.tsx b/app/assets/javascripts/components/Input.tsx new file mode 100644 index 000000000..0955b632c --- /dev/null +++ b/app/assets/javascripts/components/Input.tsx @@ -0,0 +1,22 @@ +import { FunctionalComponent } from 'preact'; + +interface Props { + text?: string; + disabled?: boolean; + className?: string; +} + +export const Input: FunctionalComponent = ({ + className = '', + disabled = false, + text, +}) => { + const base = `rounded py-1.5 px-3 text-input my-1 h-8`; + const stateClasses = disabled + ? 'no-border bg-grey-5' + : 'border-solid border-1 border-gray-300'; + const classes = `${base} ${stateClasses} ${className}`; + return ( + + ); +}; diff --git a/app/assets/javascripts/components/PreferencesMenuItem.tsx b/app/assets/javascripts/components/PreferencesMenuItem.tsx deleted file mode 100644 index eb872053a..000000000 --- a/app/assets/javascripts/components/PreferencesMenuItem.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Icon, IconType } from '@/components/Icon'; -import { FunctionComponent } from 'preact'; - -interface PreferencesMenuItemProps { - iconType: IconType; - label: string; - selected: boolean; - onClick: () => void; -} - -export const PreferencesMenuItem: FunctionComponent = - ({ iconType, label, selected, onClick }) => ( -
{ - e.preventDefault(); - onClick(); - }} - > - - {label} -
- ); diff --git a/app/assets/javascripts/components/RoundIconButton.tsx b/app/assets/javascripts/components/RoundIconButton.tsx new file mode 100644 index 000000000..d143fd4e2 --- /dev/null +++ b/app/assets/javascripts/components/RoundIconButton.tsx @@ -0,0 +1,42 @@ +import { FunctionComponent } from 'preact'; +import { Icon, IconType } from './Icon'; + +type ButtonType = 'normal' | 'primary'; + +interface Props { + /** + * onClick - preventDefault is handled within the component + */ + onClick: () => void; + + type: ButtonType; + + className?: string; + + icon: IconType; +} + +/** + * IconButton component with an icon + * preventDefault is already handled within the component + */ +export const RoundIconButton: FunctionComponent = ({ + onClick, + type, + className, + icon: iconType, +}) => { + const click = (e: MouseEvent) => { + e.preventDefault(); + onClick(); + }; + const classes = type === 'primary' ? 'info ' : ''; + return ( + + ); +}; diff --git a/app/assets/javascripts/components/Switch.tsx b/app/assets/javascripts/components/Switch.tsx index c504df77c..0a35c2a74 100644 --- a/app/assets/javascripts/components/Switch.tsx +++ b/app/assets/javascripts/components/Switch.tsx @@ -12,7 +12,7 @@ export type SwitchProps = HTMLProps & { checked?: boolean; onChange: (checked: boolean) => void; className?: string; - children: ComponentChildren; + children?: ComponentChildren; }; export const Switch: FunctionalComponent = ( @@ -22,7 +22,9 @@ export const Switch: FunctionalComponent = ( const checked = props.checked ?? checkedState; const className = props.className ?? ''; return ( -