Implemented basic Flipper theme, [Flipper] Setup initial layout and siderail
Summary:
This setups the first bits of the Sandy Layout, and has a styled siderail according to the design, that does absolutely nothing.
{gif:0sa60r8c}
Reviewed By: cekkaewnumchai
Differential Revision: D23655313
fbshipit-source-id: e30278aeae0913e231ad105a9afb55c74c6a3370
This commit is contained in:
committed by
Facebook GitHub Bot
parent
2d2a8bd675
commit
ef4379e847
@@ -10,6 +10,7 @@
|
|||||||
"privileged": true,
|
"privileged": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ant-design/icons": "^4.2.2",
|
||||||
"@emotion/core": "^10.0.22",
|
"@emotion/core": "^10.0.22",
|
||||||
"@emotion/styled": "^10.0.23",
|
"@emotion/styled": "^10.0.23",
|
||||||
"@iarna/toml": "^2.2.5",
|
"@iarna/toml": "^2.2.5",
|
||||||
|
|||||||
132
desktop/app/src/sandy-chrome/LeftRail.tsx
Normal file
132
desktop/app/src/sandy-chrome/LeftRail.tsx
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* 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, {cloneElement} from 'react';
|
||||||
|
import {styled, FlexColumn} from 'flipper';
|
||||||
|
import {Button, Divider, Badge, Tooltip} from 'antd';
|
||||||
|
import {
|
||||||
|
MobileFilled,
|
||||||
|
AppstoreOutlined,
|
||||||
|
BellOutlined,
|
||||||
|
FileExclamationOutlined,
|
||||||
|
LoginOutlined,
|
||||||
|
BugOutlined,
|
||||||
|
SettingOutlined,
|
||||||
|
QuestionCircleOutlined,
|
||||||
|
MedicineBoxOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import {SidebarLeft, SidebarRight} from './SandyIcons';
|
||||||
|
|
||||||
|
const LeftRailContainer = styled(FlexColumn)({
|
||||||
|
width: 48,
|
||||||
|
boxShadow: 'inset -1px 0px 0px rgba(0, 0, 0, 0.1)',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
});
|
||||||
|
LeftRailContainer.displayName = 'LeftRailContainer';
|
||||||
|
|
||||||
|
const LeftRailSection = styled(FlexColumn)({
|
||||||
|
padding: '8px 0px',
|
||||||
|
alignItems: 'center',
|
||||||
|
});
|
||||||
|
LeftRailSection.displayName = 'LeftRailSection';
|
||||||
|
|
||||||
|
const LeftRailButtonElem = styled(Button)<{small?: boolean}>(({small}) => ({
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
margin: small ? 2 : 6,
|
||||||
|
padding: '5px 0',
|
||||||
|
border: 'none',
|
||||||
|
}));
|
||||||
|
LeftRailButtonElem.displayName = 'LeftRailButtonElem';
|
||||||
|
|
||||||
|
function LeftRailButton({
|
||||||
|
icon,
|
||||||
|
small,
|
||||||
|
active,
|
||||||
|
count,
|
||||||
|
title,
|
||||||
|
}: {
|
||||||
|
icon?: React.ReactElement;
|
||||||
|
small?: boolean;
|
||||||
|
active?: boolean;
|
||||||
|
count?: number;
|
||||||
|
title: string;
|
||||||
|
}) {
|
||||||
|
let iconElement =
|
||||||
|
icon && cloneElement(icon, {style: {fontSize: small ? 16 : 24}});
|
||||||
|
if (count !== undefined) {
|
||||||
|
iconElement = <Badge count={count}>{iconElement}</Badge>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Tooltip title={title} placement="right">
|
||||||
|
<LeftRailButtonElem
|
||||||
|
small={small}
|
||||||
|
type={active ? 'primary' : 'ghost'}
|
||||||
|
icon={iconElement}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LeftRailDivider = styled(Divider)({
|
||||||
|
margin: 10,
|
||||||
|
width: 36,
|
||||||
|
minWidth: 36,
|
||||||
|
});
|
||||||
|
LeftRailDivider.displayName = 'LeftRailDividier';
|
||||||
|
|
||||||
|
export function LeftRail() {
|
||||||
|
return (
|
||||||
|
<LeftRailContainer>
|
||||||
|
<LeftRailSection>
|
||||||
|
<LeftRailButton icon={<MobileFilled />} active title="App Inspect" />
|
||||||
|
<LeftRailButton icon={<AppstoreOutlined />} title="Plugin Manager" />
|
||||||
|
<LeftRailButton
|
||||||
|
count={8}
|
||||||
|
icon={<BellOutlined />}
|
||||||
|
title="Notifications"
|
||||||
|
/>
|
||||||
|
<LeftRailDivider />
|
||||||
|
<LeftRailButton
|
||||||
|
icon={<FileExclamationOutlined />}
|
||||||
|
title="Flipper Logs"
|
||||||
|
/>
|
||||||
|
</LeftRailSection>
|
||||||
|
<LeftRailSection>
|
||||||
|
<LeftRailButton
|
||||||
|
icon={<MedicineBoxOutlined />}
|
||||||
|
small
|
||||||
|
title="Setup Doctor"
|
||||||
|
/>
|
||||||
|
<LeftRailButton
|
||||||
|
icon={<QuestionCircleOutlined />}
|
||||||
|
small
|
||||||
|
title="Help / Start Screen"
|
||||||
|
/>
|
||||||
|
<LeftRailButton icon={<SettingOutlined />} small title="Settings" />
|
||||||
|
<LeftRailButton
|
||||||
|
icon={<BugOutlined />}
|
||||||
|
small
|
||||||
|
title="Feedback / Bug Reporter"
|
||||||
|
/>
|
||||||
|
<LeftRailButton
|
||||||
|
icon={<SidebarLeft />}
|
||||||
|
small
|
||||||
|
title="Right Sidebar Toggle"
|
||||||
|
/>
|
||||||
|
<LeftRailButton
|
||||||
|
icon={<SidebarRight />}
|
||||||
|
small
|
||||||
|
title="Left Sidebar Toggle"
|
||||||
|
/>
|
||||||
|
<LeftRailButton icon={<LoginOutlined />} title="Log In" />
|
||||||
|
</LeftRailSection>
|
||||||
|
</LeftRailContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
139
desktop/app/src/sandy-chrome/SandyApp.tsx
Normal file
139
desktop/app/src/sandy-chrome/SandyApp.tsx
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/**
|
||||||
|
* 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 {connect} from 'react-redux';
|
||||||
|
import {State as Store} from '../reducers';
|
||||||
|
import {Settings, updateSettings} from '../reducers/settings';
|
||||||
|
import {styled, FlexColumn, colors, Text} from 'flipper';
|
||||||
|
import {DatePicker, Button} from 'antd';
|
||||||
|
import {Layout, FlexBox} from '../ui';
|
||||||
|
|
||||||
|
import {LeftRail} from './LeftRail';
|
||||||
|
import {CloseCircleOutlined} from '@ant-design/icons';
|
||||||
|
|
||||||
|
type StateFromProps = {settings: Settings};
|
||||||
|
type DispatchFromProps = {disableSandy: (settings: Settings) => void};
|
||||||
|
type OwnProps = {};
|
||||||
|
|
||||||
|
type Props = StateFromProps & DispatchFromProps & OwnProps;
|
||||||
|
|
||||||
|
const Container = styled(FlexColumn)({
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: colors.light02,
|
||||||
|
});
|
||||||
|
|
||||||
|
const Box = styled(FlexColumn)({
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
background: colors.white,
|
||||||
|
borderRadius: 10,
|
||||||
|
boxShadow: '0 1px 3px rgba(0,0,0,0.25)',
|
||||||
|
paddingBottom: 16,
|
||||||
|
});
|
||||||
|
|
||||||
|
const AnnoucementText = styled(Text)({
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 300,
|
||||||
|
textAlign: 'center',
|
||||||
|
margin: 16,
|
||||||
|
});
|
||||||
|
|
||||||
|
const LeftContainer = styled(FlexBox)({
|
||||||
|
height: '100% ',
|
||||||
|
});
|
||||||
|
|
||||||
|
// This component should be dropped, and insetTitlebar should be removed from Electron startup once Sandy is the default
|
||||||
|
const TemporarilyTitlebar = styled('div')<{focused?: boolean}>(({focused}) => ({
|
||||||
|
textAlign: 'center',
|
||||||
|
userSelect: 'none',
|
||||||
|
height: '38px',
|
||||||
|
lineHeight: '38px',
|
||||||
|
fontSize: '10pt',
|
||||||
|
color: colors.macOSTitleBarIcon,
|
||||||
|
background: true
|
||||||
|
? `linear-gradient(to bottom, ${colors.macOSTitleBarBackgroundTop} 0%, ${colors.macOSTitleBarBackgroundBottom} 100%)`
|
||||||
|
: colors.macOSTitleBarBackgroundBlur,
|
||||||
|
borderBottom: `1px solid ${
|
||||||
|
focused ? colors.macOSTitleBarBorder : colors.macOSTitleBarBorderBlur
|
||||||
|
}`,
|
||||||
|
WebkitAppRegion: 'drag',
|
||||||
|
}));
|
||||||
|
|
||||||
|
function SandyApp(props: Props) {
|
||||||
|
return (
|
||||||
|
<Layout.Top>
|
||||||
|
<TemporarilyTitlebar focused /*TODO: make dynamic */>
|
||||||
|
[Sandy] Flipper{' '}
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="link"
|
||||||
|
icon={<CloseCircleOutlined />}
|
||||||
|
onClick={() => props.disableSandy(props.settings)}></Button>
|
||||||
|
</TemporarilyTitlebar>
|
||||||
|
<Layout.Left>
|
||||||
|
<LeftContainer>
|
||||||
|
<LeftRail />
|
||||||
|
<LeftMenu />
|
||||||
|
</LeftContainer>
|
||||||
|
<Layout.Right>
|
||||||
|
<MainContainer>
|
||||||
|
<TemporarilyContent {...props} />
|
||||||
|
</MainContainer>
|
||||||
|
<RightMenu />
|
||||||
|
</Layout.Right>
|
||||||
|
</Layout.Left>
|
||||||
|
</Layout.Top>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function LeftMenu() {
|
||||||
|
return <div>LeftMenu</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function RightMenu() {
|
||||||
|
return <div>RightMenu</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MainContainer({children}: any) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
MainContainer
|
||||||
|
<br />
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TemporarilyContent(props: Props) {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Box>
|
||||||
|
<AnnoucementText>
|
||||||
|
New UI for Flipper, Sandy Project! Nothing to see now. Go back to
|
||||||
|
current Flipper
|
||||||
|
</AnnoucementText>
|
||||||
|
<DatePicker />
|
||||||
|
</Box>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
||||||
|
({settingsState}) => ({settings: settingsState}),
|
||||||
|
(dispatch) => ({
|
||||||
|
disableSandy: (settings: Settings) => {
|
||||||
|
console.log(settings);
|
||||||
|
dispatch(updateSettings({...settings, enableSandy: false}));
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)(SandyApp);
|
||||||
40
desktop/app/src/sandy-chrome/SandyIcons.tsx
Normal file
40
desktop/app/src/sandy-chrome/SandyIcons.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export const SidebarLeft = (props: React.SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg width={16} height={16} viewBox="0 0 16 16" fill="none" {...props}>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M14.667 1.333H1.333v13.334h13.334V1.333zM1.333 0C.597 0 0 .597 0 1.333v13.334C0 15.403.597 16 1.333 16h13.334c.736 0 1.333-.597 1.333-1.333V1.333C16 .597 15.403 0 14.667 0H1.333z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9.778 1.333h1.333v13.334H9.778V1.333zM11.556 3c0-.184.149-.333.333-.333h2c.184 0 .333.149.333.333v.667c0 .184-.149.333-.333.333h-2a.333.333 0 01-.333-.333V3zM11.556 5c0-.184.149-.333.333-.333h2c.184 0 .333.149.333.333v.667c0 .184-.149.333-.333.333h-2a.333.333 0 01-.333-.333V5zM11.556 7c0-.184.149-.333.333-.333h2c.184 0 .333.149.333.333v.667c0 .184-.149.333-.333.333h-2a.333.333 0 01-.333-.333V7zM11.556 9c0-.184.149-.333.333-.333h2c.184 0 .333.149.333.333v.667c0 .184-.149.333-.333.333h-2a.333.333 0 01-.333-.333V9z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SidebarRight = (props: React.SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg width={16} height={16} viewBox="0 0 16 16" fill="none" {...props}>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M14.667 1.333H1.333v13.334h13.334V1.333zM1.333 0C.597 0 0 .597 0 1.333v13.334C0 15.403.597 16 1.333 16h13.334c.736 0 1.333-.597 1.333-1.333V1.333C16 .597 15.403 0 14.667 0H1.333z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M4.889 1.333h1.333v13.334H4.89V1.333zM1.778 3c0-.184.149-.333.333-.333h2c.184 0 .333.149.333.333v.667c0 .184-.149.333-.333.333h-2a.333.333 0 01-.333-.333V3zM1.778 5c0-.184.149-.333.333-.333h2c.184 0 .333.149.333.333v.667c0 .184-.149.333-.333.333h-2a.333.333 0 01-.333-.333V5zM1.778 7c0-.184.149-.333.333-.333h2c.184 0 .333.149.333.333v.667c0 .184-.149.333-.333.333h-2a.333.333 0 01-.333-.333V7zM1.778 9c0-.184.149-.333.333-.333h2c.184 0 .333.149.333.333v.667c0 .184-.149.333-.333.333h-2a.333.333 0 01-.333-.333V9z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
@@ -1,4 +1,64 @@
|
|||||||
@import '../node_modules/antd/lib/style/themes/dark.less';
|
@import '../node_modules/antd/lib/style/themes/dark.less';
|
||||||
@import '../node_modules/antd/dist/antd.less';
|
@import '../node_modules/antd/dist/antd.less';
|
||||||
|
|
||||||
@primary-color: yellow;
|
/* Based on: https://www.figma.com/file/4e6BMdm2SuZ1L7FSuOPQVC/Flipper?node-id=620%3A84636 */
|
||||||
|
@border-radius-base: 6px;
|
||||||
|
|
||||||
|
@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||||
|
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
|
||||||
|
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
|
@code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
|
||||||
|
monospace;
|
||||||
|
|
||||||
|
// Link Text & Icon
|
||||||
|
@primary-color: @purple-8;
|
||||||
|
// Success
|
||||||
|
@success-color: @green-7;
|
||||||
|
// Negative
|
||||||
|
@error-color: @red-6;
|
||||||
|
@highlight-color: @red-6;
|
||||||
|
@badge-color: @red-6;
|
||||||
|
// Warning
|
||||||
|
@warning-color: @gold-6;
|
||||||
|
|
||||||
|
// Primary Text & Icon
|
||||||
|
@text-color: @white;
|
||||||
|
// Secondary Text & Icon
|
||||||
|
@text-color-secondary: fade(@white, 60%);
|
||||||
|
// Placeholder Text & Icon
|
||||||
|
@input-placeholder-color: fade(@white, 45%);
|
||||||
|
// Disabled & Icon
|
||||||
|
@disabled-color: fade(@white, 25%);
|
||||||
|
// Background - default
|
||||||
|
@body-background: @black; // Background color for `<body>`
|
||||||
|
// @component-background: @black; // Base background color for most components
|
||||||
|
// Background - Wash
|
||||||
|
@normal-color:fade(
|
||||||
|
@white,
|
||||||
|
5%
|
||||||
|
);
|
||||||
|
// @background-color-light: fade(
|
||||||
|
// @white,
|
||||||
|
// 5%
|
||||||
|
// ); // background of header and selected item
|
||||||
|
// Background - Wash
|
||||||
|
// @background-color-base: fade(@white, 10%); // Default grey background color
|
||||||
|
// Background - Primary Button
|
||||||
|
// @btn-primary-bg: @primary-color;
|
||||||
|
// Background - Primary Hoever
|
||||||
|
// ??? : @purple-7
|
||||||
|
// Background - Default Button
|
||||||
|
// @btn-default-bg: fade(@white, 10%);
|
||||||
|
// Background - Default Hover
|
||||||
|
// @btn-text-hover-bg: fade(@white, 15%);
|
||||||
|
// Background - Button Disabled
|
||||||
|
// @btn-disable-bg: fade(@white, 10%);
|
||||||
|
// Background - Transparent Hover
|
||||||
|
// @btn-link-hover-bg: fade(@white, 10%);
|
||||||
|
// Background - Navigation Active
|
||||||
|
// ???: fade(@white, 8%)
|
||||||
|
// Dividers and Borders
|
||||||
|
@divider-color: fade(@white, 10%);
|
||||||
|
|
||||||
|
@tooltip-color: @black;
|
||||||
|
@tooltip-bg: @white;
|
||||||
|
|||||||
@@ -1,4 +1,63 @@
|
|||||||
@import '../node_modules/antd/lib/style/themes/default.less';
|
@import '../node_modules/antd/lib/style/themes/default.less';
|
||||||
@import '../node_modules/antd/dist/antd.less';
|
@import '../node_modules/antd/dist/antd.less';
|
||||||
|
|
||||||
@primary-color: red;
|
/* Based on: https://www.figma.com/file/4e6BMdm2SuZ1L7FSuOPQVC/Flipper?node-id=620%3A84636 */
|
||||||
|
@border-radius-base: 6px;
|
||||||
|
|
||||||
|
@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||||
|
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
|
||||||
|
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
|
@code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
|
||||||
|
monospace;
|
||||||
|
|
||||||
|
// Link Text & Icon
|
||||||
|
@primary-color: @purple-7;
|
||||||
|
// Success
|
||||||
|
@success-color: @green-7;
|
||||||
|
// Negative
|
||||||
|
@error-color: @red-6;
|
||||||
|
@highlight-color: @red-6;
|
||||||
|
// Warning
|
||||||
|
@warning-color: @gold-6;
|
||||||
|
|
||||||
|
// Primary Text & Icon
|
||||||
|
@text-color: @black;
|
||||||
|
// Secondary Text & Icon
|
||||||
|
@text-color-secondary: fade(@black, 60%);
|
||||||
|
// Placeholder Text & Icon
|
||||||
|
@input-placeholder-color: fade(@black, 45%);
|
||||||
|
// Disabled & Icon
|
||||||
|
@disabled-color: fade(@black, 25%);
|
||||||
|
// Background - default
|
||||||
|
@body-background: @white; // Background color for `<body>`
|
||||||
|
// @component-background: @white; // Base background color for most components
|
||||||
|
// Background - Wash
|
||||||
|
@normal-color:fade(
|
||||||
|
@black,
|
||||||
|
5%
|
||||||
|
);
|
||||||
|
// @background-color-light: fade(
|
||||||
|
// @black,
|
||||||
|
// 5%
|
||||||
|
// ); // background of header and selected item
|
||||||
|
// Background - Wash
|
||||||
|
// @background-color-base: fade(@black, 10%); // Default grey background color
|
||||||
|
// Background - Primary Button
|
||||||
|
// @btn-primary-bg: @primary-color;
|
||||||
|
// Background - Primary Hoever
|
||||||
|
// ??? : @purple-7
|
||||||
|
// Background - Default Button
|
||||||
|
// @btn-default-bg: fade(@black, 10%);
|
||||||
|
// Background - Default Hover
|
||||||
|
// @btn-text-hover-bg: fade(@black, 15%);
|
||||||
|
// Background - Button Disabled
|
||||||
|
// @btn-disable-bg: fade(@black, 10%);
|
||||||
|
// Background - Transparent Hover
|
||||||
|
// @btn-link-hover-bg: fade(@black, 10%);
|
||||||
|
// Background - Navigation Active
|
||||||
|
// ???: fade(@black, 8%)
|
||||||
|
// Dividers and Borders
|
||||||
|
@divider-color: fade(@black, 10%);
|
||||||
|
|
||||||
|
@tooltip-color: @white;
|
||||||
|
@tooltip-bg: @black;
|
||||||
|
|||||||
Reference in New Issue
Block a user