More shaving on design system
Summary: Added standardized dimensions for padding and gap, to encourage people to build layouts that look consistent, using for example `padv="small"` Reviewed By: cekkaewnumchai Differential Revision: D23961386 fbshipit-source-id: 33cd3b8974858e021a8b7d1b32f018fe3f007c63
This commit is contained in:
committed by
Facebook GitHub Bot
parent
e8370e9fc1
commit
b105574d00
@@ -27,6 +27,7 @@ import {notNull} from './utils/typeUtils';
|
||||
import constants from './fb-stubs/constants';
|
||||
import {Logger} from './fb-interfaces/Logger';
|
||||
import {NormalizedMenuEntry, buildInMenuEntries} from 'flipper-plugin';
|
||||
import {StyleGuide} from './sandy-chrome/StyleGuide';
|
||||
|
||||
export type DefaultKeyboardAction = keyof typeof buildInMenuEntries;
|
||||
export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help';
|
||||
@@ -339,6 +340,12 @@ function getTemplate(
|
||||
store.dispatch(setActiveSheet(ACTIVE_SHEET_PLUGINS));
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Flipper style guide',
|
||||
click() {
|
||||
store.dispatch(setStaticView(StyleGuide));
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Toggle Developer Tools',
|
||||
accelerator: (function () {
|
||||
|
||||
@@ -37,12 +37,10 @@ export function AppInspect() {
|
||||
<SidebarTitle actions={<InfoIcon>{appTooltip}</InfoIcon>}>
|
||||
App Inspect
|
||||
</SidebarTitle>
|
||||
<Layout.Vertical
|
||||
padding={`${theme.space.small}px ${theme.space.medium}px`}
|
||||
gap={theme.space.large}>
|
||||
<Layout.Vertical padv="small" padh="medium" gap={theme.space.large}>
|
||||
<DeviceDropdown />
|
||||
<Input addonAfter={<SettingOutlined />} defaultValue="mysite" />
|
||||
<Layout.Horizontal gap={theme.space.small}>
|
||||
<Layout.Horizontal gap>
|
||||
<Button icon={<SettingOutlined />} type="link" />
|
||||
<Button icon={<SettingOutlined />} type="link" />
|
||||
<Button icon={<SettingOutlined />} type="link" />
|
||||
|
||||
@@ -72,14 +72,14 @@ const demos: PreviewProps[] = [
|
||||
props: [
|
||||
['rounded', 'boolean (false)', 'Make the corners rounded'],
|
||||
[
|
||||
'padded',
|
||||
'boolean (false)',
|
||||
'Use a standard small padding for this container (use `padding` for non-default padding)',
|
||||
'padv / padh / pad',
|
||||
Object.keys(theme.space).join(' | ') + ' | number | true',
|
||||
'Short-hand to set the horizontal, vertical or both paddings. The keys correspond to the theme space settings. Using `true` picks the default horizontal / vertical padding for inline elements.',
|
||||
],
|
||||
[
|
||||
'padding',
|
||||
'CSS Padding',
|
||||
'Short-hand to set the style.padding property',
|
||||
'width / height',
|
||||
'number',
|
||||
'Set the width / height of this container in pixels. Use sparingly.',
|
||||
],
|
||||
[
|
||||
'bordered',
|
||||
@@ -87,25 +87,10 @@ const demos: PreviewProps[] = [
|
||||
'This container will use a default border on all sides',
|
||||
],
|
||||
[
|
||||
'borderTop',
|
||||
'borderTop / borderRight / borderBottom / borderLeft',
|
||||
'boolean (false)',
|
||||
'Use a standard padding on the top side',
|
||||
],
|
||||
[
|
||||
'borderRight',
|
||||
'boolean (false)',
|
||||
'Use a standard padding on the right side',
|
||||
],
|
||||
[
|
||||
'borderBottom',
|
||||
'boolean (false)',
|
||||
'Use a standard padding on the bottom side',
|
||||
],
|
||||
[
|
||||
'borderLeft',
|
||||
'boolean (false)',
|
||||
'Use a standard padding on the left side',
|
||||
],
|
||||
],
|
||||
demos: {
|
||||
'Basic container with fixed dimensions': (
|
||||
@@ -149,8 +134,8 @@ const demos: PreviewProps[] = [
|
||||
props: [
|
||||
[
|
||||
'gap',
|
||||
'number (0)',
|
||||
'Set the spacing between children. Typically theme.space.small should be used.',
|
||||
Object.keys(theme.space).join(' | ') + ' | number | true',
|
||||
'Set the spacing between children. For `true` theme.space.small should be used. Defaults to 0.',
|
||||
],
|
||||
[
|
||||
'center',
|
||||
@@ -159,8 +144,8 @@ const demos: PreviewProps[] = [
|
||||
],
|
||||
],
|
||||
demos: {
|
||||
'Basic usage, gap={24}': (
|
||||
<Layout.Horizontal gap={24}>
|
||||
'Basic usage, gap="large"': (
|
||||
<Layout.Horizontal gap="large">
|
||||
{aButton}
|
||||
{someText}
|
||||
{aBox}
|
||||
@@ -287,11 +272,11 @@ const demos: PreviewProps[] = [
|
||||
function ComponentPreview({title, demos, description, props}: PreviewProps) {
|
||||
return (
|
||||
<Card title={title} size="small" type="inner">
|
||||
<Layout.Vertical gap={theme.space.small}>
|
||||
<Layout.Vertical gap="small">
|
||||
<Text type="secondary">{description}</Text>
|
||||
<Collapse ghost>
|
||||
<Collapse.Panel header="Examples" key="demos">
|
||||
<Layout.Vertical gap={theme.space.large}>
|
||||
<Layout.Vertical gap="large">
|
||||
{Object.entries(demos).map(([name, children]) => (
|
||||
<div key={name}>
|
||||
<Tabs type="line">
|
||||
|
||||
@@ -31,13 +31,6 @@ import {errorCounterAtom} from '../chrome/ConsoleLogs';
|
||||
import {ToplevelProps} from './SandyApp';
|
||||
import {useValue} from 'flipper-plugin';
|
||||
|
||||
const LeftRailContainer = styled(Layout.Bottom)({
|
||||
width: 48,
|
||||
borderRight: `1px solid ${theme.dividerColor}`,
|
||||
padding: `${theme.paddingLarge}px ${theme.paddingSmall}px`,
|
||||
});
|
||||
LeftRailContainer.displayName = 'LeftRailContainer';
|
||||
|
||||
const LeftRailButtonElem = styled(Button)<{kind?: 'small'}>(({kind}) => ({
|
||||
width: kind === 'small' ? 32 : 36,
|
||||
height: kind === 'small' ? 32 : 36,
|
||||
@@ -97,46 +90,48 @@ export function LeftRail({
|
||||
setToplevelSelection,
|
||||
}: ToplevelProps) {
|
||||
return (
|
||||
<LeftRailContainer>
|
||||
<Layout.Vertical center gap={10}>
|
||||
<LeftRailButton
|
||||
icon={<MobileFilled />}
|
||||
title="App Inspect"
|
||||
selected={toplevelSelection === 'appinspect'}
|
||||
onClick={() => {
|
||||
setToplevelSelection('appinspect');
|
||||
}}
|
||||
/>
|
||||
<LeftRailButton icon={<AppstoreOutlined />} title="Plugin Manager" />
|
||||
<LeftRailButton icon={<BellOutlined />} title="Notifications" />
|
||||
<LeftRailDivider />
|
||||
<DebugLogsButton
|
||||
toplevelSelection={toplevelSelection}
|
||||
setToplevelSelection={setToplevelSelection}
|
||||
/>
|
||||
</Layout.Vertical>
|
||||
<Layout.Vertical center gap={10}>
|
||||
<LeftRailButton
|
||||
icon={<MedicineBoxOutlined />}
|
||||
small
|
||||
title="Setup Doctor"
|
||||
/>
|
||||
<WelcomeScreenButton />
|
||||
<ShowSettingsButton />
|
||||
<LeftRailButton
|
||||
icon={<BugOutlined />}
|
||||
small
|
||||
title="Feedback / Bug Reporter"
|
||||
/>
|
||||
<LeftRailButton
|
||||
icon={<SidebarRight />}
|
||||
small
|
||||
title="Right Sidebar Toggle"
|
||||
/>
|
||||
<LeftSidebarToggleButton />
|
||||
<LeftRailButton icon={<LoginOutlined />} title="Log In" />
|
||||
</Layout.Vertical>
|
||||
</LeftRailContainer>
|
||||
<Layout.Container borderRight padv={12} padh={6} width={48}>
|
||||
<Layout.Bottom>
|
||||
<Layout.Vertical center gap={10}>
|
||||
<LeftRailButton
|
||||
icon={<MobileFilled />}
|
||||
title="App Inspect"
|
||||
selected={toplevelSelection === 'appinspect'}
|
||||
onClick={() => {
|
||||
setToplevelSelection('appinspect');
|
||||
}}
|
||||
/>
|
||||
<LeftRailButton icon={<AppstoreOutlined />} title="Plugin Manager" />
|
||||
<LeftRailButton icon={<BellOutlined />} title="Notifications" />
|
||||
<LeftRailDivider />
|
||||
<DebugLogsButton
|
||||
toplevelSelection={toplevelSelection}
|
||||
setToplevelSelection={setToplevelSelection}
|
||||
/>
|
||||
</Layout.Vertical>
|
||||
<Layout.Vertical center gap={10}>
|
||||
<LeftRailButton
|
||||
icon={<MedicineBoxOutlined />}
|
||||
small
|
||||
title="Setup Doctor"
|
||||
/>
|
||||
<WelcomeScreenButton />
|
||||
<ShowSettingsButton />
|
||||
<LeftRailButton
|
||||
icon={<BugOutlined />}
|
||||
small
|
||||
title="Feedback / Bug Reporter"
|
||||
/>
|
||||
<LeftRailButton
|
||||
icon={<SidebarRight />}
|
||||
small
|
||||
title="Right Sidebar Toggle"
|
||||
/>
|
||||
<LeftSidebarToggleButton />
|
||||
<LeftRailButton icon={<LoginOutlined />} title="Log In" />
|
||||
</Layout.Vertical>
|
||||
</Layout.Bottom>
|
||||
</Layout.Container>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@ import {Button, Tooltip, Typography} from 'antd';
|
||||
import {InfoCircleOutlined} from '@ant-design/icons';
|
||||
|
||||
export const LeftSidebar: React.FC = ({children}) => (
|
||||
<Layout.Vertical borderRight padding={`${theme.space.small}px 0`}>
|
||||
{children}
|
||||
</Layout.Vertical>
|
||||
<Layout.Container borderRight padv="small">
|
||||
<Layout.Vertical>{children}</Layout.Vertical>
|
||||
</Layout.Container>
|
||||
);
|
||||
|
||||
export function SidebarTitle({
|
||||
@@ -36,7 +36,7 @@ export function SidebarTitle({
|
||||
}
|
||||
|
||||
const LeftMenuTitle = styled(Layout.Horizontal)({
|
||||
padding: `0px ${theme.paddingLarge}px`,
|
||||
padding: `0px ${theme.inlinePaddingH}px`,
|
||||
lineHeight: `${theme.space.large}px`,
|
||||
fontSize: theme.fontSize.smallBody,
|
||||
textTransform: 'uppercase',
|
||||
|
||||
@@ -91,11 +91,7 @@ export function SandyApp({logger}: {logger: Logger}) {
|
||||
setToplevelSelection={setToplevelSelection}
|
||||
/>
|
||||
<Sidebar width={250} minWidth={220} maxWidth={800} gutter>
|
||||
{leftMenuContent && (
|
||||
<Layout.Container borderRight>
|
||||
{leftMenuContent}
|
||||
</Layout.Container>
|
||||
)}
|
||||
{leftMenuContent && leftMenuContent}
|
||||
</Sidebar>
|
||||
</Layout.Horizontal>
|
||||
<MainContainer>
|
||||
|
||||
@@ -18,9 +18,9 @@ const {Title, Text, Link} = Typography;
|
||||
|
||||
export default function SandyDesignSystem() {
|
||||
return (
|
||||
<Layout.ScrollContainer className={resetLists}>
|
||||
<Layout.Vertical gap={theme.space.large}>
|
||||
<Card title="Flipper Design System">
|
||||
<Layout.ScrollContainer className={reset}>
|
||||
<Layout.Vertical gap="large">
|
||||
<Card title="Flipper Design System" bordered={false}>
|
||||
<p>
|
||||
Welcome to the Flipper Design System. The Flipper design system is
|
||||
based on{' '}
|
||||
@@ -57,7 +57,7 @@ export default function SandyDesignSystem() {
|
||||
</li>
|
||||
</ul>
|
||||
</Card>
|
||||
<Card title="Colors">
|
||||
<Card title="Colors" bordered={false}>
|
||||
<Alert message="The following colors are available on the <code>theme</code> object. Please stick to this color palette, as these colors will be translated to dark mode correctly." />
|
||||
<ColorPreview name="primaryColor" />
|
||||
<ColorPreview name="successColor" />
|
||||
@@ -72,7 +72,7 @@ export default function SandyDesignSystem() {
|
||||
<ColorPreview name="backgroundTransparentHover" />
|
||||
<ColorPreview name="dividerColor" />
|
||||
</Card>
|
||||
<Card title="Typography">
|
||||
<Card title="Typography" bordered={false}>
|
||||
<Space direction="vertical">
|
||||
<Alert
|
||||
message={
|
||||
@@ -106,7 +106,7 @@ export default function SandyDesignSystem() {
|
||||
<Input placeholder="Input" />
|
||||
</Space>
|
||||
</Card>
|
||||
<Card title="Theme variables">
|
||||
<Card title="Theme variables" bordered={false}>
|
||||
<Alert
|
||||
message={
|
||||
<>
|
||||
@@ -118,7 +118,7 @@ export default function SandyDesignSystem() {
|
||||
/>
|
||||
<pre>{JSON.stringify(theme, null, 2)}</pre>
|
||||
</Card>
|
||||
<Card title="Layout components">
|
||||
<Card title="Layout components" bordered={false}>
|
||||
<DesignComponentDemos />
|
||||
</Card>
|
||||
</Layout.Vertical>
|
||||
@@ -146,7 +146,7 @@ function ColorPreview({name}: {name: keyof typeof theme}) {
|
||||
);
|
||||
}
|
||||
|
||||
const resetLists = css`
|
||||
const reset = css`
|
||||
ol,
|
||||
ul {
|
||||
list-style: revert;
|
||||
@@ -155,4 +155,7 @@ const resetLists = css`
|
||||
.ant-alert {
|
||||
margin-bottom: ${theme.space.huge}px;
|
||||
}
|
||||
.ant-card {
|
||||
background: transparent;
|
||||
}
|
||||
`;
|
||||
|
||||
15
desktop/app/src/sandy-chrome/StyleGuide.tsx
Normal file
15
desktop/app/src/sandy-chrome/StyleGuide.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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 from 'react';
|
||||
import SandyDesignSystem from './SandyDesignSystem';
|
||||
|
||||
export function StyleGuide() {
|
||||
return <SandyDesignSystem />;
|
||||
}
|
||||
@@ -26,8 +26,8 @@ export const theme = {
|
||||
dividerColor: 'var(--flipper-divider-color)',
|
||||
borderRadius: 'var(--flipper-border-radius)',
|
||||
containerBorderRadius: 8,
|
||||
paddingSmall: 6, // vertical padding on inline elements like buttons
|
||||
paddingLarge: 12, // horizontal ,,,
|
||||
inlinePaddingV: 6, // vertical padding on inline elements like buttons
|
||||
inlinePaddingH: 12, // horizontal ,,,
|
||||
space: {
|
||||
// from Space component in Ant
|
||||
tiny: 4,
|
||||
@@ -51,3 +51,35 @@ export function useIsDarkMode(): boolean {
|
||||
(state) => state.settingsState.enableSandy && state.settingsState.darkMode,
|
||||
);
|
||||
}
|
||||
|
||||
export type Spacing = keyof typeof theme['space'] | number | undefined | true;
|
||||
|
||||
export type PaddingProps = {
|
||||
padv?: Spacing;
|
||||
padh?: Spacing;
|
||||
pad?: Spacing;
|
||||
};
|
||||
|
||||
export function normalizePadding({
|
||||
padv,
|
||||
padh,
|
||||
pad,
|
||||
}: PaddingProps): string | undefined {
|
||||
if (padv === undefined && padh === undefined && pad === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return `${normalizeSpace(
|
||||
padv ?? pad ?? 0,
|
||||
theme.inlinePaddingV,
|
||||
)}px ${normalizeSpace(padh ?? pad ?? 0, theme.inlinePaddingH)}px`;
|
||||
}
|
||||
|
||||
export function normalizeSpace(spacing: Spacing, defaultSpace: number): number {
|
||||
return spacing === true
|
||||
? defaultSpace
|
||||
: spacing === undefined
|
||||
? 0
|
||||
: typeof spacing === 'string'
|
||||
? theme.space[spacing]
|
||||
: spacing;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,13 @@
|
||||
|
||||
import React, {CSSProperties} from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import {theme} from '../../sandy-chrome/theme';
|
||||
import {
|
||||
normalizePadding,
|
||||
normalizeSpace,
|
||||
PaddingProps,
|
||||
Spacing,
|
||||
theme,
|
||||
} from '../../sandy-chrome/theme';
|
||||
import {useIsSandy} from '../../sandy-chrome/SandyContext';
|
||||
import {renderLayout} from './LegacyLayout';
|
||||
|
||||
@@ -17,7 +23,6 @@ type ContainerProps = {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
padding?: CSSProperties['padding'];
|
||||
borderBottom?: boolean;
|
||||
borderTop?: boolean;
|
||||
borderRight?: boolean;
|
||||
@@ -25,7 +30,9 @@ type ContainerProps = {
|
||||
bordered?: boolean;
|
||||
rounded?: boolean;
|
||||
padded?: boolean;
|
||||
};
|
||||
width?: number;
|
||||
height?: number;
|
||||
} & PaddingProps;
|
||||
|
||||
const Container = styled.div<ContainerProps>(
|
||||
({
|
||||
@@ -34,13 +41,16 @@ const Container = styled.div<ContainerProps>(
|
||||
borderLeft,
|
||||
borderRight,
|
||||
borderTop,
|
||||
padding,
|
||||
rounded,
|
||||
padded,
|
||||
width,
|
||||
height,
|
||||
...rest
|
||||
}) => ({
|
||||
width,
|
||||
height,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: padded ? theme.space.small : padding,
|
||||
padding: normalizePadding(rest),
|
||||
borderRadius: rounded ? theme.containerBorderRadius : undefined,
|
||||
flex: 1,
|
||||
borderStyle: 'solid',
|
||||
@@ -79,7 +89,7 @@ type DistributionProps = ContainerProps & {
|
||||
/**
|
||||
* Gab between individual items
|
||||
*/
|
||||
gap?: CSSProperties['gap'];
|
||||
gap?: Spacing;
|
||||
/**
|
||||
* If set, items will be aligned in the center, if false (the default) items will be stretched.
|
||||
*/
|
||||
@@ -89,14 +99,14 @@ type DistributionProps = ContainerProps & {
|
||||
const Horizontal = styled(Container)<DistributionProps>(({gap, center}) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
gap,
|
||||
gap: normalizeSpace(gap, theme.space.small),
|
||||
alignItems: center ? 'center' : 'stretch',
|
||||
}));
|
||||
|
||||
const Vertical = styled(Container)<DistributionProps>(({gap, center}) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap,
|
||||
gap: normalizeSpace(gap, theme.space.small),
|
||||
alignItems: center ? 'center' : 'stretch',
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user