diff options
| author | Haishan <[email protected]> | 2020-03-20 22:19:56 +0800 |
|---|---|---|
| committer | Haishan <[email protected]> | 2020-03-21 13:33:43 +0800 |
| commit | 8e48c01e7aada6978e92a6da1d040f3ef0d37945 (patch) | |
| tree | 63cdf772b88d2cff340449ba98225bdbad526a19 /src/components | |
| parent | c5d70b5236be5ce0fb067bab3c8eeb6e946a73dd (diff) | |
feat: remembers group collapse state
for https://github.com/haishanh/yacd/issues/480
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/Button.js | 21 | ||||
| -rw-r--r-- | src/components/CollapsibleSectionHeader.js | 2 | ||||
| -rw-r--r-- | src/components/CollapsibleSectionHeader.module.css | 4 | ||||
| -rw-r--r-- | src/components/ProxyGroup.js | 20 | ||||
| -rw-r--r-- | src/components/ProxyProvider.js | 33 | ||||
| -rw-r--r-- | src/components/StateProvider.js | 2 |
6 files changed, 61 insertions, 21 deletions
diff --git a/src/components/Button.js b/src/components/Button.js index d5b88cf..2ec0c22 100644 --- a/src/components/Button.js +++ b/src/components/Button.js @@ -16,10 +16,17 @@ type ButtonProps = { isLoading?: boolean, start?: Element | (() => Element), onClick?: (SyntheticEvent<HTMLButtonElement>) => mixed, - kind?: 'primary' | 'minimal' + kind?: 'primary' | 'minimal', + className?: string }; function Button(props: ButtonProps, ref) { - const { onClick, isLoading, kind = 'primary', ...restProps } = props; + const { + onClick, + isLoading, + kind = 'primary', + className, + ...restProps + } = props; const internalOnClick = useCallback( e => { if (isLoading) return; @@ -27,9 +34,13 @@ function Button(props: ButtonProps, ref) { }, [isLoading, onClick] ); - const btnClassName = cx(s0.btn, { - [s0.minimal]: kind === 'minimal' - }); + const btnClassName = cx( + s0.btn, + { + [s0.minimal]: kind === 'minimal' + }, + className + ); return ( <button className={btnClassName} ref={ref} onClick={internalOnClick}> {isLoading ? ( diff --git a/src/components/CollapsibleSectionHeader.js b/src/components/CollapsibleSectionHeader.js index aebb643..3cd0a96 100644 --- a/src/components/CollapsibleSectionHeader.js +++ b/src/components/CollapsibleSectionHeader.js @@ -24,7 +24,7 @@ export default function Header({ name, type, toggle, isOpen, qty }: Props) { {typeof qty === 'number' ? <span className={s.qty}>{qty}</span> : null} - <Button kind="minimal" onClick={toggle}> + <Button kind="minimal" onClick={toggle} className={s.btn}> <span className={cx(s.arrow, { [s.isOpen]: isOpen })}> <ChevronDown size={20} /> </span> diff --git a/src/components/CollapsibleSectionHeader.module.css b/src/components/CollapsibleSectionHeader.module.css index de24eec..854a0c6 100644 --- a/src/components/CollapsibleSectionHeader.module.css +++ b/src/components/CollapsibleSectionHeader.module.css @@ -16,6 +16,10 @@ } } +.btn { + margin-left: 5px; +} + /* TODO duplicate with connQty in Connections.module.css */ .qty { font-family: var(--font-normal); diff --git a/src/components/ProxyGroup.js b/src/components/ProxyGroup.js index fffb020..d7cf203 100644 --- a/src/components/ProxyGroup.js +++ b/src/components/ProxyGroup.js @@ -2,11 +2,11 @@ import React from 'react'; import cx from 'classnames'; import memoizeOne from 'memoize-one'; -import { connect } from './StateProvider'; +import { connect, useStoreActions } from './StateProvider'; import { getProxies, getRtFilterSwitch } from '../store/proxies'; +import { getCollapsibleIsOpen } from '../store/app'; import CollapsibleSectionHeader from './CollapsibleSectionHeader'; import Proxy, { ProxySmall } from './Proxy'; -import { useToggle } from '../hooks/basic'; import s0 from './ProxyGroup.module.css'; @@ -14,9 +14,17 @@ import { switchProxy } from '../store/proxies'; const { useCallback, useMemo } = React; -function ProxyGroup({ name, all, type, now, apiConfig, dispatch }) { +function ProxyGroup({ name, all, type, now, isOpen, apiConfig, dispatch }) { const isSelectable = useMemo(() => type === 'Selector', [type]); - const [isOpen, toggle] = useToggle(true); + + const { + app: { updateCollapsibleIsOpen } + } = useStoreActions(); + + const toggle = useCallback(() => { + updateCollapsibleIsOpen('proxyGroup', name, !isOpen); + }, [isOpen, updateCollapsibleIsOpen, name]); + const itemOnTapCallback = useCallback( proxyName => { if (!isSelectable) return; @@ -161,11 +169,13 @@ export function ProxyListSummaryView({ export default connect((s, { name, delay }) => { const proxies = getProxies(s); const filterByRt = getRtFilterSwitch(s); + const collapsibleIsOpen = getCollapsibleIsOpen(s); const group = proxies[name]; const { all, type, now } = group; return { all: filterAvailableProxiesAndSort(all, delay, filterByRt), type, - now + now, + isOpen: collapsibleIsOpen[`proxyGroup:${name}`] }; })(ProxyGroup); diff --git a/src/components/ProxyProvider.js b/src/components/ProxyProvider.js index 32071ab..9486128 100644 --- a/src/components/ProxyProvider.js +++ b/src/components/ProxyProvider.js @@ -3,7 +3,7 @@ import { RotateCw, Zap } from 'react-feather'; import { formatDistance } from 'date-fns'; import { motion } from 'framer-motion'; -import { connect } from './StateProvider'; +import { connect, useStoreActions } from './StateProvider'; import Collapsible from './Collapsible'; import CollapsibleSectionHeader from './CollapsibleSectionHeader'; import { @@ -13,7 +13,7 @@ import { } from './ProxyGroup'; import Button from './Button'; -import { getClashAPIConfig } from '../store/app'; +import { getClashAPIConfig, getCollapsibleIsOpen } from '../store/app'; import { getDelay, getRtFilterSwitch, @@ -31,7 +31,8 @@ type Props = { type: 'Proxy' | 'Rule', vehicleType: 'HTTP' | 'File' | 'Compatible', updatedAt?: string, - dispatch: any => void + dispatch: any => void, + isOpen: boolean }; function ProxyProvider({ @@ -39,6 +40,7 @@ function ProxyProvider({ proxies, vehicleType, updatedAt, + isOpen, dispatch, apiConfig }: Props) { @@ -53,8 +55,17 @@ function ProxyProvider({ setIsHealthcheckLoading(false); }, [apiConfig, dispatch, name, setIsHealthcheckLoading]); - const [isCollapsibleOpen, setCollapsibleOpen] = useState(false); - const toggle = useCallback(() => setCollapsibleOpen(x => !x), []); + const { + app: { updateCollapsibleIsOpen } + } = useStoreActions(); + + // const [isCollapsibleOpen, setCollapsibleOpen] = useState(false); + // const toggle = useCallback(() => setCollapsibleOpen(x => !x), []); + + const toggle = useCallback(() => { + updateCollapsibleIsOpen('proxyProvider', name, !isOpen); + }, [isOpen, updateCollapsibleIsOpen, name]); + const timeAgo = formatDistance(new Date(updatedAt), new Date()); return ( <div className={s.body}> @@ -62,13 +73,13 @@ function ProxyProvider({ name={name} toggle={toggle} type={vehicleType} - isOpen={isCollapsibleOpen} + isOpen={isOpen} qty={proxies.length} /> <div className={s.updatedAt}> <small>Updated {timeAgo} ago</small> </div> - <Collapsible isOpen={isCollapsibleOpen}> + <Collapsible isOpen={isOpen}> <ProxyList all={proxies} /> <div className={s.actionFooter}> <Button text="Update" start={<Refresh />} onClick={updateProvider} /> @@ -80,7 +91,7 @@ function ProxyProvider({ /> </div> </Collapsible> - <Collapsible isOpen={!isCollapsibleOpen}> + <Collapsible isOpen={!isOpen}> <ProxyListSummaryView all={proxies} /> </Collapsible> </div> @@ -112,13 +123,15 @@ function Refresh() { ); } -const mapState = (s, { proxies }) => { +const mapState = (s, { proxies, name }) => { const filterByRt = getRtFilterSwitch(s); const delay = getDelay(s); + const collapsibleIsOpen = getCollapsibleIsOpen(s); const apiConfig = getClashAPIConfig(s); return { apiConfig, - proxies: filterAvailableProxiesAndSort(proxies, delay, filterByRt) + proxies: filterAvailableProxiesAndSort(proxies, delay, filterByRt), + isOpen: collapsibleIsOpen[`proxyProvider:${name}`] }; }; diff --git a/src/components/StateProvider.js b/src/components/StateProvider.js index 30b1cda..e675f89 100644 --- a/src/components/StateProvider.js +++ b/src/components/StateProvider.js @@ -99,6 +99,8 @@ function bindActions(actions, dispatch) { const action = actions[key]; if (typeof action === 'function') { boundActions[key] = bindAction(action, dispatch); + } else if (typeof action === 'object') { + boundActions[key] = bindActions(action, dispatch); } } return boundActions; |
