diff options
| author | Marco Rodolfi <marco.rodolfi@tuta.io> | 2023-06-19 15:23:27 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-06-19 06:23:27 -0700 |
| commit | 57f4555350c669e4cb098b48691975be79838468 (patch) | |
| tree | f840889c0c344ed5ae56a0f06398a97ca5982d2b /frontend/src/components/modals/DropdownMultiselect.tsx | |
| parent | bd87cc852b935369bba04130801467b8dbeb6d1c (diff) | |
| download | decky-loader-57f4555350c669e4cb098b48691975be79838468.tar.gz decky-loader-57f4555350c669e4cb098b48691975be79838468.zip | |
[Feature] File picker improvements (#454)
* First iteration for internationalization of the loader
* First iteration for internationalization of the loader
* Cleanup node mess
* Cleanup node mess pt2
* Additional touches
* Latest decky changed merged into i18n and updated translation.
* Styling fixes
* Initial backend hosting implementation
* Added correct url path of the loopback server.
* Added correct url path of the loopback server.
* Some better namespaced text.
* Added whitelist for locales path.
* Refactor languages and fix hooks logic bugs.
* Small typo in language translation structure.
* Working backend, automatically swtich languages with steam and language fixes.
* Fix to languages
* Key fixes
* Additional language fixes.
* Additional json changes
* Final text revision and added a vscode tasks to automatically extract text from code.
* Typo in the middleware
* Remove unused imports
* Cleanup whitespaces.
* Import changes
* Revert "Import changes"
This reverts commit 8e8231950fd7cc6cece87040e326d0a72ba79567.
* Update index.d.ts
* Clean up unused imports
* Delete pnpm-lock.yaml
* Update rollup.config.js
* Update PluginInstallModal.tsx
* Update index.tsx
* Update plugin-loader.tsx
* Update plugin-loader.tsx
* Revert "Delete pnpm-lock.yaml"
This reverts commit 3a39f36f2193cc976d36ffe07338239e363d5b04.
* Additional strings reworks.
* Fixes for issues coming from github merge.
* Fixes for master
* Styling fixes
* Styling pt2
* Missed a few strings in master,
* Styling fixes
* Additional master merge fixes.
* Final cleanup and adaptation to master.
* Final empty language cleanup and few string added
* Small changes to italian translation
* Disabled translation on a few components inside plugin-loader for missing react hooks.
* Fixed passing tag to translation.
* Disable debug output for reducing console spam.
* Return correct content type
* Small italian language change
* Added support for country code
* Fixed missing translation for uninstall popup.
* Fix class name shenanigans for toast notification
* Update dependencies
* Fixed github workflow to include the new locales folder
* Update dependencies to latest version (unless it's React) and fixed the new small errors that cropped up
* Missed a file name change
* Updated dev dependencies to latest version
* Missed a few dev dependencies
* Revert "Update dependencies to latest version (unless it's React) and fixed the new small errors that cropped up"
Messed up merge with a different main branch
* Messed up deletion of rollup config.
* Fix broken pnpm lock file
* Missed a localized string during the merge
* Fixed a parameter mistake in the uninstall text parameter
* Fix pnpm random issues
* Small italian language tweaks
* Fix wrong parameter passed to the uninstall function call
* Another fix on a wrong function parameter
* Additional translation text on the store and branch selection channels
* Changed the default type passed to map to being able to index the two arrays.
* Reverted and reworked the last changes
* Distinguish events in UI for installing vs reinstalling plugins
* Additional fixes for reinstall prompt
* Revert the use of intevalPlural since the parser doesn't seem to support that.
* Missed a routing path in the backend
* Small bugfixes
* Small fixes
* Correctly adding the parameter to the request headers.
* Refactoring of the UI popup modal
* Fix pnpm shenanigans
* Final fixes for the install UI localization
* Clean up unnedeed backend code
* Small rework on text selection.
* Cleaned up parser configuration
* Removed extracttext dependency to pnpmsetup
* Merged translation and cleaned up parser
* Fixed JSON structure after manual merge.
* Added translation to the file picker
* First iteration for merging the new filepicker.
* Revert changes to PluginInstallModal
* Reworked the text modal for the final time
* Missed the proper linted text
* Missed the backend change
* Final branch cleanup
* First iteration for porting the new file picker
* Hotfix for i18n where the detector was overriding localStorage
* Please, pnpm, cooperate
* Small fix regarding the backend getting hammered when switching to not supported languages plus a small english typo
* Initial working upstream iteration for file picker
* Typo on translation variable
* File picker final improvements
* Stylistic fixes and fix on wrong bool passed to fp
* Fixup merge from main
* Other merge errors fixed
* Minor cleanups
* Fixed missing padding under text label extension
* Implement pagination backend side
* First draft for filtering backend side
* Implemented matching on file names.
* Fix for unable to order per size on folders.
* Hard checking a return value
* Added a missing import.
* Implemented show more as a frontend button
* Whoops, python typo
* Fixed python backend
* Rendering bug fix and small qol improvement
* Added missing parameter to openFilePicker call
* Fixed path on windows and unknown error on wrong path
* Small backend fixes
* Extension fix
* Simplified extension logic
* Less string conversions.
* Optimize backend code and removed additional components.
* Take correctly into account the max value
The button will now respect the actual maximum desired number of entries.
* Bugfix for ordering logic and ignore cases during sorting
* Regex call was missing an argument
* Fixed issues with filtering extensions
* Rollback testing changes
* Minor cleanup and attempt at fixing the not updating multimodal.
* Cleanup variable types.
* Mantains the same api format from the original source code.
* Removing hardcoded paths in the code
* Additional fixes for resolving the user path
* Cleanup useless modifications
* Final fixes for avoid path hardcoding
* Update lockfile and i18next version
Diffstat (limited to 'frontend/src/components/modals/DropdownMultiselect.tsx')
| -rw-r--r-- | frontend/src/components/modals/DropdownMultiselect.tsx | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/frontend/src/components/modals/DropdownMultiselect.tsx b/frontend/src/components/modals/DropdownMultiselect.tsx new file mode 100644 index 00000000..5defbfa4 --- /dev/null +++ b/frontend/src/components/modals/DropdownMultiselect.tsx @@ -0,0 +1,121 @@ +import { + DialogButton, + DialogCheckbox, + DialogCheckboxProps, + Marquee, + Menu, + MenuItem, + findModuleChild, + showContextMenu, +} from 'decky-frontend-lib'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { FaChevronDown } from 'react-icons/fa'; + +const dropDownControlButtonClass = findModuleChild((m) => { + if (typeof m !== 'object') return undefined; + for (const prop in m) { + if (m[prop]?.toString()?.includes('gamepaddropdown_DropDownControlButton')) { + return m[prop]; + } + } +}); + +const DropdownMultiselectItem: FC< + { + value: any; + onSelect: (checked: boolean, value: any) => void; + checked: boolean; + } & DialogCheckboxProps +> = ({ value, onSelect, checked: defaultChecked, ...rest }) => { + const [checked, setChecked] = useState(defaultChecked); + + useEffect(() => { + onSelect?.(checked, value); + }, [checked, onSelect, value]); + + return ( + <MenuItem bInteractableItem onClick={() => setChecked((x) => !x)}> + <DialogCheckbox + style={{ marginBottom: 0, padding: 0 }} + className="decky_DropdownMultiselectItem_DialogCheckbox" + bottomSeparator="none" + {...rest} + onClick={() => setChecked((x) => !x)} + onChange={(checked) => setChecked(checked)} + controlled + checked={checked} + /> + </MenuItem> + ); +}; + +const DropdownMultiselect: FC<{ + items: { + label: string; + value: string; + }[]; + selected: string[]; + onSelect: (selected: any[]) => void; + label: string; +}> = ({ label, items, selected, onSelect }) => { + const [itemsSelected, setItemsSelected] = useState<any>(selected); + const { t } = useTranslation(); + + const handleItemSelect = useCallback((checked, value) => { + setItemsSelected((x: any) => + checked ? [...x.filter((y: any) => y !== value), value] : x.filter((y: any) => y !== value), + ); + }, []); + + useEffect(() => { + onSelect(itemsSelected); + }, [itemsSelected, onSelect]); + + return ( + <DialogButton + style={{ + display: 'flex', + alignItems: 'center', + maxWidth: '100%', + }} + className={dropDownControlButtonClass} + onClick={(evt) => { + evt.preventDefault(); + showContextMenu( + <Menu label={label} cancelText={t('DropdownMultiselect.button.back') as string}> + <style> + {` + /* Inherit color from ".basiccontextmenu" */ + .decky_DropdownMultiselectItem_DialogCheckbox > .DialogToggle_Label { + color: inherit; + } + `} + </style> + <div style={{ marginTop: '10px' }}>{/*FIXME: Hack for missing padding under label menu*/}</div> + {items.map((x) => ( + <DropdownMultiselectItem + key={x.value} + label={x.label} + value={x.value} + checked={itemsSelected.includes(x.value)} + onSelect={handleItemSelect} + /> + ))} + </Menu>, + evt.currentTarget ?? window, + ); + }} + > + <Marquee> + {selected.length > 0 + ? selected.map((x: any) => items[items.findIndex((v) => v.value === x)].label).join(', ') + : '…'} + </Marquee> + <div style={{ flexGrow: 1, minWidth: '1ch' }} /> + <FaChevronDown style={{ height: '1em', flex: '0 0 1em' }} /> + </DialogButton> + ); +}; + +export default DropdownMultiselect; |
