diff --git a/src/App.tsx b/src/App.tsx index e491969c0..53e60ef87 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -11,7 +11,8 @@ import React from 'react'; import {FlexColumn, FlexRow} from 'flipper'; import {connect} from 'react-redux'; import TitleBar from './chrome/TitleBar'; -import MainSidebar from './chrome/MainSidebar'; +import MainSidebar from './chrome/mainsidebar/MainSidebar'; +import MainSidebar2 from './chrome/mainsidebar/MainSidebar2'; import BugReporterDialog from './chrome/BugReporterDialog'; import ErrorBar from './chrome/ErrorBar'; import DoctorBar from './chrome/DoctorBar'; @@ -45,6 +46,8 @@ import PluginManager from './chrome/PluginManager'; import StatusBar from './chrome/StatusBar'; import SettingsSheet from './chrome/SettingsSheet'; import DoctorSheet from './chrome/DoctorSheet'; +import GK from './fb-stubs/GK'; + const version = remote.app.getVersion(); type OwnProps = { @@ -139,7 +142,8 @@ export class App extends React.Component { {this.getSheet} - {this.props.leftSidebarVisible && } + {this.props.leftSidebarVisible && + (GK.get('flipper_sidebar2') ? : )} {this.props.staticView != null ? ( React.createElement(this.props.staticView, { logger: this.props.logger, diff --git a/src/chrome/MainSidebar.tsx b/src/chrome/mainsidebar/MainSidebar.tsx similarity index 69% rename from src/chrome/MainSidebar.tsx rename to src/chrome/mainsidebar/MainSidebar.tsx index 9e1f5b896..f3f6e2bc5 100644 --- a/src/chrome/MainSidebar.tsx +++ b/src/chrome/mainsidebar/MainSidebar.tsx @@ -7,20 +7,17 @@ * @format */ -import config from '../fb-stubs/config'; -import BaseDevice from '../devices/BaseDevice'; -import Client from '../Client'; -import {UninitializedClient} from '../UninitializedClient'; -import {FlipperBasePlugin, sortPluginsByName} from '../plugin'; -import {PluginNotification} from '../reducers/notifications'; -import {ActiveSheet, ACTIVE_SHEET_PLUGINS} from '../reducers/application'; -import {State as Store} from '../reducers'; +import BaseDevice from '../../devices/BaseDevice'; +import Client from '../../Client'; +import {UninitializedClient} from '../../UninitializedClient'; +import {FlipperBasePlugin, sortPluginsByName} from '../../plugin'; +import {PluginNotification} from '../../reducers/notifications'; +import {ActiveSheet} from '../../reducers/application'; +import {State as Store} from '../../reducers'; import { Sidebar, - FlexBox, colors, brandColors, - Text, Glyph, styled, FlexColumn, @@ -37,7 +34,6 @@ import { Info, } from 'flipper'; import React, {Component, PureComponent, Fragment} from 'react'; -import NotificationScreen from '../chrome/NotificationScreen'; import { selectPlugin, starPlugin, @@ -46,33 +42,20 @@ import { selectClient, getAvailableClients, getClientById, -} from '../reducers/connections'; -import {setActiveSheet} from '../reducers/application'; -import UserAccount from './UserAccount'; +} from '../../reducers/connections'; +import {setActiveSheet} from '../../reducers/application'; import {connect} from 'react-redux'; -import {BackgroundColorProperty} from 'csstype'; -import SupportRequestFormManager from '../fb-stubs/SupportRequestFormManager'; -import SupportRequestDetails from '../fb-stubs/SupportRequestDetails'; -import SupportRequestFormV2 from '../fb-stubs/SupportRequestFormV2'; -import WatchTools from '../fb-stubs/WatchTools'; - -type FlipperPlugins = typeof FlipperPlugin[]; -type PluginsByCategory = [string, FlipperPlugins][]; - -const ListItem = styled.div<{active?: boolean}>(({active}) => ({ - paddingLeft: 10, - display: 'flex', - alignItems: 'center', - marginBottom: 6, - flexShrink: 0, - backgroundColor: active ? colors.macOSTitleBarIconSelected : 'none', - color: active ? colors.white : colors.macOSSidebarSectionItem, - lineHeight: '25px', - padding: '0 10px', - '&[disabled]': { - color: 'rgba(0, 0, 0, 0.5)', - }, -})); +import SupportRequestFormManager from '../../fb-stubs/SupportRequestFormManager'; +import SupportRequestDetails from '../../fb-stubs/SupportRequestDetails'; +import MainSidebarUtils from './MainSidebarUtilsSection'; +import { + ListItem, + isStaticViewActive, + FlipperPlugins, + PluginsByCategory, + PluginName, + PluginIcon, +} from './sidebarUtils'; const SidebarButton = styled(Button)<{small?: boolean}>(({small}) => ({ fontWeight: 'bold', @@ -88,48 +71,6 @@ const SidebarButton = styled(Button)<{small?: boolean}>(({small}) => ({ whiteSpace: 'nowrap', })); -const PluginShape = styled(FlexBox)<{ - backgroundColor?: BackgroundColorProperty; -}>(({backgroundColor}) => ({ - marginRight: 8, - backgroundColor, - borderRadius: 3, - flexShrink: 0, - width: 18, - height: 18, - justifyContent: 'center', - alignItems: 'center', - top: '-1px', -})); - -const PluginName = styled(Text)<{isActive?: boolean; count?: number}>( - props => ({ - minWidth: 0, - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - overflow: 'hidden', - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', - flexGrow: 1, - '::after': { - fontSize: 12, - display: props.count ? 'inline-block' : 'none', - padding: '0 8px', - lineHeight: '17px', - height: 17, - alignSelf: 'center', - content: `"${props.count}"`, - borderRadius: '999em', - color: props.isActive ? colors.macOSTitleBarIconSelected : colors.white, - backgroundColor: props.isActive - ? colors.white - : colors.macOSTitleBarIconSelected, - fontWeight: 500, - }, - }), -); - const CategoryName = styled(PluginName)({ color: colors.macOSSidebarSectionTitle, textTransform: 'uppercase', @@ -141,24 +82,6 @@ const Plugins = styled(FlexColumn)({ overflow: 'auto', }); -function PluginIcon({ - isActive, - backgroundColor, - name, - color, -}: { - isActive: boolean; - backgroundColor?: string; - name: string; - color: string; -}) { - return ( - - - - ); -} - class PluginSidebarListItem extends Component<{ onClick: () => void; isActive: boolean; @@ -254,28 +177,13 @@ type DispatchFromProps = { type Props = OwnProps & StateFromProps & DispatchFromProps; type State = { - showSupportForm: boolean; - showWatchDebugRoot: boolean; showAllPlugins: boolean; }; + class MainSidebar extends PureComponent { state: State = { - showSupportForm: GK.get('support_requests_v2'), - showWatchDebugRoot: GK.get('watch_team_flipper_clientless_access'), showAllPlugins: false, }; - static getDerivedStateFromProps(props: Props, state: State) { - if ( - !state.showSupportForm && - props.staticView === SupportRequestFormManager - ) { - // Show SupportForm option even when GK is false and support form is shown. - // That means the user has used deeplink to open support form. - // Once the variable is true, it will be true for the whole session. - return {showSupportForm: true}; - } - return state; - } render() { const { @@ -283,9 +191,7 @@ class MainSidebar extends PureComponent { selectClient, selectedPlugin, selectedApp, - staticView, selectPlugin, - setStaticView, uninitializedClients, } = this.props; const clients = getAvailableClients(selectedDevice, this.props.clients); @@ -376,52 +282,7 @@ class MainSidebar extends PureComponent { )} - {this.state.showWatchDebugRoot && - (function() { - const active = isStaticViewActive(staticView, WatchTools); - return ( - setStaticView(WatchTools)}> - - Watch - - ); - })()} - {this.renderNotificationsEntry()} - {this.state.showSupportForm && - (function() { - const active = isStaticViewActive(staticView, SupportRequestFormV2); - return ( - setStaticView(SupportRequestFormV2)}> - - Litho Support Request - - ); - })()} - this.props.setActiveSheet(ACTIVE_SHEET_PLUGINS)}> - - Manage Plugins - - {config.showLogin && } + ); } @@ -435,6 +296,9 @@ class MainSidebar extends PureComponent { staticView, SupportRequestDetails, ); + const showSupportForm = + GK.get('support_requests_v2') || + isStaticViewActive(staticView, SupportRequestFormManager); return ( <> @@ -442,7 +306,7 @@ class MainSidebar extends PureComponent { {selectedDevice.source ? 'Imported device' : 'Archived device'} - {this.state.showSupportForm && + {showSupportForm && (selectedDevice as ArchivedDevice).supportRequestDetails && ( { ); } - - renderNotificationsEntry() { - if (GK.get('flipper_disable_notifications')) { - return null; - } - - const active = isStaticViewActive( - this.props.staticView, - NotificationScreen, - ); - return ( - this.props.setStaticView(NotificationScreen)} - style={{ - borderTop: `1px solid ${colors.blackAlpha10}`, - }}> - 0 ? 'bell' : 'bell-null'} - isActive={active} - /> - - Notifications - - - ); - } -} - -function isStaticViewActive( - current: StaticView, - selected: StaticView, -): boolean { - return current && selected && current === selected; } function getFavoritePlugins( diff --git a/src/chrome/mainsidebar/MainSidebar2.tsx b/src/chrome/mainsidebar/MainSidebar2.tsx new file mode 100644 index 000000000..f3f6e2bc5 --- /dev/null +++ b/src/chrome/mainsidebar/MainSidebar2.tsx @@ -0,0 +1,519 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import BaseDevice from '../../devices/BaseDevice'; +import Client from '../../Client'; +import {UninitializedClient} from '../../UninitializedClient'; +import {FlipperBasePlugin, sortPluginsByName} from '../../plugin'; +import {PluginNotification} from '../../reducers/notifications'; +import {ActiveSheet} from '../../reducers/application'; +import {State as Store} from '../../reducers'; +import { + Sidebar, + colors, + brandColors, + Glyph, + styled, + FlexColumn, + GK, + FlipperPlugin, + FlipperDevicePlugin, + LoadingIndicator, + Button, + StarButton, + Heading, + Spacer, + ArchivedDevice, + SmallText, + Info, +} from 'flipper'; +import React, {Component, PureComponent, Fragment} from 'react'; +import { + selectPlugin, + starPlugin, + StaticView, + setStaticView, + selectClient, + getAvailableClients, + getClientById, +} from '../../reducers/connections'; +import {setActiveSheet} from '../../reducers/application'; +import {connect} from 'react-redux'; +import SupportRequestFormManager from '../../fb-stubs/SupportRequestFormManager'; +import SupportRequestDetails from '../../fb-stubs/SupportRequestDetails'; +import MainSidebarUtils from './MainSidebarUtilsSection'; +import { + ListItem, + isStaticViewActive, + FlipperPlugins, + PluginsByCategory, + PluginName, + PluginIcon, +} from './sidebarUtils'; + +const SidebarButton = styled(Button)<{small?: boolean}>(({small}) => ({ + fontWeight: 'bold', + fontSize: small ? 11 : 14, + width: '100%', + overflow: 'hidden', + marginTop: small ? 0 : 20, + pointer: 'cursor', + border: 'none', + background: 'none', + padding: 0, + justifyContent: 'left', + whiteSpace: 'nowrap', +})); + +const CategoryName = styled(PluginName)({ + color: colors.macOSSidebarSectionTitle, + textTransform: 'uppercase', + fontSize: '0.9em', +}); + +const Plugins = styled(FlexColumn)({ + flexGrow: 1, + overflow: 'auto', +}); + +class PluginSidebarListItem extends Component<{ + onClick: () => void; + isActive: boolean; + plugin: typeof FlipperBasePlugin; + app?: string | null | undefined; + helpRef?: any; + provided?: any; + onFavorite?: () => void; + starred?: boolean; +}> { + render() { + const {isActive, plugin, onFavorite, starred} = this.props; + const app = this.props.app || 'Facebook'; + let iconColor: string | undefined = (brandColors as any)[app]; + + if (!iconColor) { + const pluginColors = [ + colors.seaFoam, + colors.teal, + colors.lime, + colors.lemon, + colors.orange, + colors.tomato, + colors.cherry, + colors.pink, + colors.grape, + ]; + + iconColor = pluginColors[parseInt(app, 36) % pluginColors.length]; + } + + return ( + + + {plugin.title || plugin.id} + {starred !== undefined && ( + + )} + + ); + } +} + +const Spinner = centerInSidebar(LoadingIndicator); + +const ErrorIndicator = centerInSidebar(Glyph); + +function centerInSidebar(component: any) { + return styled(component)({ + marginTop: '10px', + marginBottom: '10px', + marginLeft: 'auto', + marginRight: 'auto', + }); +} + +type OwnProps = {}; + +type StateFromProps = { + numNotifications: number; + windowIsFocused: boolean; + selectedDevice: BaseDevice | null | undefined; + staticView: StaticView; + selectedPlugin: string | null | undefined; + selectedApp: string | null | undefined; + userStarredPlugins: Store['connections']['userStarredPlugins']; + clients: Array; + uninitializedClients: Array<{ + client: UninitializedClient; + deviceId?: string; + errorMessage?: string; + }>; + devicePlugins: Map; + clientPlugins: Map; +}; + +type DispatchFromProps = { + selectPlugin: (payload: { + selectedPlugin: string | null; + selectedApp: string | null; + deepLinkPayload: string | null; + }) => void; + selectClient: typeof selectClient; + setActiveSheet: (activeSheet: ActiveSheet) => void; + setStaticView: (payload: StaticView) => void; + starPlugin: typeof starPlugin; +}; + +type Props = OwnProps & StateFromProps & DispatchFromProps; +type State = { + showAllPlugins: boolean; +}; + +class MainSidebar extends PureComponent { + state: State = { + showAllPlugins: false, + }; + + render() { + const { + selectedDevice, + selectClient, + selectedPlugin, + selectedApp, + selectPlugin, + uninitializedClients, + } = this.props; + const clients = getAvailableClients(selectedDevice, this.props.clients); + const client: Client | undefined = getClientById(clients, selectedApp); + + return ( + + + {selectedDevice ? ( + <> + + {selectedDevice.title} + + {this.showArchivedDeviceDetails(selectedDevice)} + {selectedDevice.devicePlugins.map(pluginName => { + const plugin = this.props.devicePlugins.get(pluginName)!; + return ( + + selectPlugin({ + selectedPlugin: plugin.id, + selectedApp: null, + deepLinkPayload: null, + }) + } + plugin={plugin} + /> + ); + })} + + ({ + checked: client === c, + label: c.query.app, + type: 'checkbox', + click: () => selectClient(c.id), + }))}> + {clients.length === 0 ? ( + <> + + No clients connected + + ) : !client ? ( + 'Select client' + ) : ( + <> + {client.query.app} + + + )} + + + {this.renderClientPlugins(client)} + {uninitializedClients.map(entry => ( + + {entry.client.appName} + {entry.errorMessage ? ( + + ) : ( + + )} + + ))} + + ) : ( + + + + Select a device to get started + + )} + + + + ); + } + + showArchivedDeviceDetails(selectedDevice: BaseDevice) { + if (!selectedDevice.isArchived || !selectedDevice.source) { + return null; + } + const {staticView, setStaticView} = this.props; + const supportRequestDetailsactive = isStaticViewActive( + staticView, + SupportRequestDetails, + ); + const showSupportForm = + GK.get('support_requests_v2') || + isStaticViewActive(staticView, SupportRequestFormManager); + return ( + <> + + + {selectedDevice.source ? 'Imported device' : 'Archived device'} + + + {showSupportForm && + (selectedDevice as ArchivedDevice).supportRequestDetails && ( + setStaticView(SupportRequestDetails)}> + + + Support Request Details + + + )} + + ); + } + + renderPluginsByCategory( + client: Client, + plugins: FlipperPlugins, + starred: boolean, + onFavorite: (pluginId: string) => void, + ) { + const {selectedPlugin, selectedApp, selectPlugin} = this.props; + return groupPluginsByCategory(plugins).map(([category, plugins]) => ( + + {category && ( + + {category} + + )} + {plugins.map(plugin => ( + + selectPlugin({ + selectedPlugin: plugin.id, + selectedApp: client.id, + deepLinkPayload: null, + }) + } + plugin={plugin} + app={client.query.app} + onFavorite={() => onFavorite(plugin.id)} + starred={starred} + /> + ))} + + )); + } + + renderClientPlugins(client?: Client) { + if (!client) { + return null; + } + const onFavorite = (plugin: string) => { + this.props.starPlugin({ + selectedApp: client.query.app, + selectedPlugin: plugin, + }); + }; + const allPlugins = Array.from(this.props.clientPlugins.values()).filter( + (p: typeof FlipperPlugin) => client.plugins.indexOf(p.id) > -1, + ); + const favoritePlugins: FlipperPlugins = getFavoritePlugins( + allPlugins, + this.props.userStarredPlugins[client.query.app], + true, + ); + const showAllPlugins = + this.state.showAllPlugins || + favoritePlugins.length === 0 || + // If the plugin is part of the hidden section, make sure sidebar is expanded + (client.plugins.includes(this.props.selectedPlugin!) && + !favoritePlugins.find( + plugin => plugin.id === this.props.selectedPlugin, + )); + return ( + <> + {favoritePlugins.length === 0 ? ( + + Star your favorite plugins! + + ) : ( + <> + {this.renderPluginsByCategory( + client, + favoritePlugins, + true, + onFavorite, + )} + + + this.setState(state => ({ + ...state, + showAllPlugins: !state.showAllPlugins, + })) + }> + {showAllPlugins ? 'Show less' : 'Show more'} + + + + + )} +
+ {showAllPlugins + ? this.renderPluginsByCategory( + client, + getFavoritePlugins( + allPlugins, + this.props.userStarredPlugins[client.query.app], + false, + ), + false, + onFavorite, + ) + : null} +
+ + ); + } +} + +function getFavoritePlugins( + allPlugins: FlipperPlugins, + starredPlugins: undefined | string[], + favorite: boolean, +): FlipperPlugins { + if (!starredPlugins || !starredPlugins.length) { + return favorite ? [] : allPlugins; + } + return allPlugins.filter(plugin => { + const idx = starredPlugins.indexOf(plugin.id); + return idx === -1 ? !favorite : favorite; + }); +} + +function groupPluginsByCategory(plugins: FlipperPlugins): PluginsByCategory { + const sortedPlugins = plugins.slice().sort(sortPluginsByName); + const byCategory: {[cat: string]: FlipperPlugins} = {}; + const res: PluginsByCategory = []; + sortedPlugins.forEach(plugin => { + const category = plugin.category || ''; + (byCategory[category] || (byCategory[category] = [])).push(plugin); + }); + // Sort categories + Object.keys(byCategory) + .sort() + .forEach(category => { + res.push([category, byCategory[category]]); + }); + return res; +} + +export default connect( + ({ + application: {windowIsFocused}, + connections: { + selectedDevice, + selectedPlugin, + selectedApp, + userStarredPlugins, + clients, + uninitializedClients, + staticView, + }, + notifications: {activeNotifications, blacklistedPlugins}, + plugins: {devicePlugins, clientPlugins}, + }) => ({ + numNotifications: (() => { + const blacklist = new Set(blacklistedPlugins); + return activeNotifications.filter( + (n: PluginNotification) => !blacklist.has(n.pluginId), + ).length; + })(), + windowIsFocused, + selectedDevice, + staticView, + selectedPlugin, + selectedApp, + userStarredPlugins, + clients, + uninitializedClients, + devicePlugins, + clientPlugins, + }), + { + selectPlugin, + selectClient, + setStaticView, + setActiveSheet, + starPlugin, + }, +)(MainSidebar); diff --git a/src/chrome/mainsidebar/MainSidebarUtilsSection.tsx b/src/chrome/mainsidebar/MainSidebarUtilsSection.tsx new file mode 100644 index 000000000..51458a6ce --- /dev/null +++ b/src/chrome/mainsidebar/MainSidebarUtilsSection.tsx @@ -0,0 +1,179 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import React, {useRef} from 'react'; +import {connect} from 'react-redux'; +import {colors, GK} from 'flipper'; + +import config from '../../fb-stubs/config'; +import {PluginNotification} from '../../reducers/notifications'; +import {ActiveSheet, ACTIVE_SHEET_PLUGINS} from '../../reducers/application'; +import {State as Store} from '../../reducers'; +import NotificationScreen from '../NotificationScreen'; +import {StaticView, setStaticView} from '../../reducers/connections'; +import {setActiveSheet} from '../../reducers/application'; +import UserAccount from '../UserAccount'; +import SupportRequestFormManager from '../../fb-stubs/SupportRequestFormManager'; +import SupportRequestFormV2 from '../../fb-stubs/SupportRequestFormV2'; +import WatchTools from '../../fb-stubs/WatchTools'; +import { + isStaticViewActive, + PluginIcon, + PluginName, + ListItem, +} from './sidebarUtils'; + +type OwnProps = {}; + +type StateFromProps = { + staticView: StaticView; +}; + +type DispatchFromProps = { + setActiveSheet: (activeSheet: ActiveSheet) => void; + setStaticView: (payload: StaticView) => void; +}; + +type Props = OwnProps & StateFromProps & DispatchFromProps; + +function MainSidebarUtilsSection({ + staticView, + setActiveSheet, + setStaticView, +}: Props) { + const showWatchDebugRoot = GK.get('watch_team_flipper_clientless_access'); + + const hasSeenSupportForm = useRef(false); + const showSupportForm = + GK.get('support_requests_v2') || + isStaticViewActive(staticView, SupportRequestFormManager) || + hasSeenSupportForm.current; + if (showSupportForm) { + hasSeenSupportForm.current = true; + } + + return ( + <> + {' '} + {showWatchDebugRoot && + (function() { + const active = isStaticViewActive(staticView, WatchTools); + return ( + setStaticView(WatchTools)}> + + Watch + + ); + })()} + + {showSupportForm && + (function() { + const active = isStaticViewActive(staticView, SupportRequestFormV2); + return ( + setStaticView(SupportRequestFormV2)}> + + Litho Support Request + + ); + })()} + setActiveSheet(ACTIVE_SHEET_PLUGINS)}> + + Manage Plugins + + {config.showLogin && } + + ); +} + +export default connect( + ({connections: {staticView}}) => ({ + staticView, + }), + { + setStaticView, + setActiveSheet, + }, +)(MainSidebarUtilsSection); + +type RenderNotificationsEntryProps = { + numNotifications: number; + staticView: StaticView; +}; + +type RenderNotificationsEntryDispatchFromProps = { + setStaticView: (payload: StaticView) => void; +}; + +type RenderEntryProps = RenderNotificationsEntryProps & + RenderNotificationsEntryDispatchFromProps; + +const RenderNotificationsEntry = connect< + RenderNotificationsEntryProps, + RenderNotificationsEntryDispatchFromProps, + {}, + Store +>( + ({ + connections: {staticView}, + notifications: {activeNotifications, blacklistedPlugins}, + }) => ({ + numNotifications: (() => { + const blacklist = new Set(blacklistedPlugins); + return activeNotifications.filter( + (n: PluginNotification) => !blacklist.has(n.pluginId), + ).length; + })(), + staticView, + }), + { + setStaticView, + }, +)(({staticView, setStaticView, numNotifications}: RenderEntryProps) => { + if (GK.get('flipper_disable_notifications')) { + return null; + } + + const active = isStaticViewActive(staticView, NotificationScreen); + return ( + setStaticView(NotificationScreen)} + style={{ + borderTop: `1px solid ${colors.blackAlpha10}`, + }}> + 0 ? 'bell' : 'bell-null'} + isActive={active} + /> + + Notifications + + + ); +}); diff --git a/src/chrome/mainsidebar/sidebarUtils.tsx b/src/chrome/mainsidebar/sidebarUtils.tsx new file mode 100644 index 000000000..d7f8d869b --- /dev/null +++ b/src/chrome/mainsidebar/sidebarUtils.tsx @@ -0,0 +1,98 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import {FlexBox, colors, Text, Glyph, styled, FlipperPlugin} from 'flipper'; +import React from 'react'; +import {StaticView} from '../../reducers/connections'; +import {BackgroundColorProperty} from 'csstype'; + +export type FlipperPlugins = typeof FlipperPlugin[]; +export type PluginsByCategory = [string, FlipperPlugins][]; + +export const ListItem = styled.div<{active?: boolean}>(({active}) => ({ + paddingLeft: 10, + display: 'flex', + alignItems: 'center', + marginBottom: 6, + flexShrink: 0, + backgroundColor: active ? colors.macOSTitleBarIconSelected : 'none', + color: active ? colors.white : colors.macOSSidebarSectionItem, + lineHeight: '25px', + padding: '0 10px', + '&[disabled]': { + color: 'rgba(0, 0, 0, 0.5)', + }, +})); + +export function PluginIcon({ + isActive, + backgroundColor, + name, + color, +}: { + isActive: boolean; + backgroundColor?: string; + name: string; + color: string; +}) { + return ( + + + + ); +} + +export const PluginShape = styled(FlexBox)<{ + backgroundColor?: BackgroundColorProperty; +}>(({backgroundColor}) => ({ + marginRight: 8, + backgroundColor, + borderRadius: 3, + flexShrink: 0, + width: 18, + height: 18, + justifyContent: 'center', + alignItems: 'center', + top: '-1px', +})); + +export const PluginName = styled(Text)<{isActive?: boolean; count?: number}>( + props => ({ + minWidth: 0, + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + overflow: 'hidden', + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', + flexGrow: 1, + '::after': { + fontSize: 12, + display: props.count ? 'inline-block' : 'none', + padding: '0 8px', + lineHeight: '17px', + height: 17, + alignSelf: 'center', + content: `"${props.count}"`, + borderRadius: '999em', + color: props.isActive ? colors.macOSTitleBarIconSelected : colors.white, + backgroundColor: props.isActive + ? colors.white + : colors.macOSTitleBarIconSelected, + fontWeight: 500, + }, + }), +); + +export function isStaticViewActive( + current: StaticView, + selected: StaticView, +): boolean { + return current && selected && current === selected; +} diff --git a/static/icons.json b/static/icons.json index 90c22804e..b97ee9299 100644 --- a/static/icons.json +++ b/static/icons.json @@ -290,5 +290,8 @@ ], "crop": [ 16 + ], + "play": [ + 16 ] -} +} \ No newline at end of file