Merge pull request #655 from bigcapitalhq/ui-tweaks

feat: Datatable UI improvements
This commit is contained in:
Ahmed Bouhuolia
2024-09-04 14:02:43 +02:00
committed by GitHub
27 changed files with 142 additions and 217 deletions

View File

@@ -1,13 +1,14 @@
// @ts-nocheck
import React, { useContext } from 'react';
import classNames from 'classnames';
import { camelCase} from 'lodash';
import { camelCase } from 'lodash';
import { If, Skeleton } from '@/components';
import { useAppIntlContext } from '@/components/AppIntlProvider';
import TableContext from './TableContext';
import { saveInvoke, ignoreEventFromSelectors } from '@/utils';
import { isCellLoading } from './utils';
import { MoneyDisplay } from '../Money/MoneyDisplay';
const ROW_CLICK_SELECTORS_INGORED = ['.expand-toggle', '.selection-checkbox'];
@@ -58,7 +59,7 @@ export default function TableCell({ cell, row, index }) {
return;
}
saveInvoke(onCellClick, cell, event);
};
};
const cellType = camelCase(cell.column.Cell.cellType) || 'text';
return (
@@ -109,7 +110,11 @@ export default function TableCell({ cell, row, index }) {
</span>
</If>
{cell.render('Cell')}
{cell.column?.money ? (
<MoneyDisplay>{cell.render('Cell')}</MoneyDisplay>
) : (
<>{cell.render('Cell')}</>
)}
</div>
</div>
);

View File

@@ -0,0 +1,4 @@
.root {
font-variant-numeric: tabular-nums;
}

View File

@@ -0,0 +1,9 @@
import styles from './MoneyDisplay.module.scss';
interface MoneyDisplayProps {
children: React.ReactNode;
}
export function MoneyDisplay({ children }: MoneyDisplayProps) {
return <span className={styles.root}>{children}</span>;
}

View File

@@ -27,6 +27,7 @@ export const useManualJournalsColumns = () => {
accessor: 'formatted_amount',
width: 115,
clickable: true,
money: true,
align: 'right',
className: clsx(CLASSES.FONT_BOLD),
},

View File

@@ -1,7 +1,8 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import { Intent, Tag } from '@blueprintjs/core';
import { Intent, Tag, Classes } from '@blueprintjs/core';
import clsx from 'classnames';
import { If, AppToaster } from '@/components';
import { NormalCell, BalanceCell, BankBalanceCell } from './components';
@@ -73,7 +74,7 @@ export const useAccountsTableColumns = () => {
id: 'type',
Header: intl.get('type'),
accessor: 'account_type_label',
className: 'type',
className: clsx('type', Classes.TEXT_MUTED),
width: 140,
clickable: true,
textOverview: true,
@@ -91,6 +92,7 @@ export const useAccountsTableColumns = () => {
id: 'currency',
Header: intl.get('currency'),
accessor: 'currency_code',
className: clsx(Classes.TEXT_MUTED),
width: 75,
clickable: true,
},
@@ -102,6 +104,7 @@ export const useAccountsTableColumns = () => {
width: 150,
clickable: true,
align: 'right',
money: true,
},
{
id: 'balance',
@@ -110,6 +113,7 @@ export const useAccountsTableColumns = () => {
Cell: BalanceCell,
width: 150,
clickable: true,
money: true,
align: 'right',
},
],

View File

@@ -1,10 +1,8 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import { Intent } from '@blueprintjs/core';
import * as R from 'ramda';
import {
DataTable,
TableFastCell,
TableSkeletonRows,
TableSkeletonHeader,
@@ -17,9 +15,10 @@ import { useMemorizedColumnsWidths } from '@/hooks';
import { useExcludedTransactionsColumns } from './_utils';
import { useExcludedTransactionsBoot } from './ExcludedTransactionsTableBoot';
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { useUnexcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
import { ActionsMenu } from './_components';
import { useUnexcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
import { BankAccountDataTable } from '../components/BankAccountDataTable';
import {
WithBankingActionsProps,
withBankingActions,
@@ -78,7 +77,7 @@ function ExcludedTransactionsTableRoot({
};
return (
<CashflowTransactionsTable
<BankAccountDataTable
noInitialFetch={true}
columns={columns}
data={excludedBankTransactions}
@@ -116,42 +115,3 @@ function ExcludedTransactionsTableRoot({
export const ExcludedTransactionsTable = R.compose(withBankingActions)(
ExcludedTransactionsTableRoot,
);
const DashboardConstrantTable = styled(DataTable)`
.table {
.thead {
.th {
background: #fff;
letter-spacing: 1px;
text-transform: uppercase;
font-size: 13px;
}
}
.tbody {
.tr:last-child .td {
border-bottom: 0;
}
}
}
`;
const CashflowTransactionsTable = styled(DashboardConstrantTable)`
.table .tbody {
.tbody-inner .tr.no-results {
.td {
padding: 2rem 0;
font-size: 14px;
color: #888;
font-weight: 400;
border-bottom: 0;
}
}
.tbody-inner {
.tr .td {
border-bottom: 1px solid #e6e6e6;
}
}
}
`;

View File

@@ -54,12 +54,14 @@ export function useExcludedTransactionsColumns() {
accessor: 'formatted_deposit_amount',
align: 'right',
width: depositWidth,
money: true
},
{
Header: 'Withdrawal',
accessor: 'formatted_withdrawal_amount',
align: 'right',
width: withdrawalWidth,
money: true
},
],
[],

View File

@@ -1,9 +1,6 @@
// @ts-nocheck
import React from 'react';
import clsx from 'classnames';
import styled from 'styled-components';
import {
DataTable,
TableFastCell,
TableSkeletonRows,
TableSkeletonHeader,
@@ -16,6 +13,7 @@ import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { usePendingTransactionsContext } from './PendingTransactionsTableBoot';
import { usePendingTransactionsTableColumns } from './_hooks';
import { BankAccountDataTable } from '../components/BankAccountDataTable';
import { compose } from '@/utils';
/**
@@ -37,7 +35,7 @@ function PendingTransactionsDataTableRoot({
} = usePendingTransactionsContext();
return (
<CashflowTransactionsTable
<BankAccountDataTable
noInitialFetch={true}
columns={columns}
data={pendingTransactions || []}
@@ -54,7 +52,6 @@ function PendingTransactionsDataTableRoot({
vListOverscanRowCount={0}
noResults={'There is no pending transactions in the current account.'}
windowScrollerProps={{ scrollElement: scrollableRef }}
className={clsx('table-constrant')}
/>
);
}
@@ -65,47 +62,3 @@ export const PendingTransactionsDataTable = compose(
})),
withBankingActions,
)(PendingTransactionsDataTableRoot);
const DashboardConstrantTable = styled(DataTable)`
.table {
.thead {
.th {
background: #fff;
text-transform: uppercase;
letter-spacing: 1px;
font-size: 13px;i
font-weight: 500;
}
}
.tbody {
.tr:last-child .td {
border-bottom: 0;
}
}
}
`;
const CashflowTransactionsTable = styled(DashboardConstrantTable)`
.table .tbody {
.tbody-inner .tr.no-results {
.td {
padding: 2rem 0;
font-size: 14px;
color: #888;
font-weight: 400;
border-bottom: 0;
}
}
.tbody-inner {
.tr .td:not(:first-child) {
border-left: 1px solid #e6e6e6;
}
.td-description {
color: #5f6b7c;
}
}
}
`;

View File

@@ -48,6 +48,7 @@ export function usePendingTransactionsTableColumns() {
textOverview: true,
align: 'right',
clickable: true,
money: true
},
{
id: 'withdrawal',
@@ -58,6 +59,7 @@ export function usePendingTransactionsTableColumns() {
textOverview: true,
align: 'right',
clickable: true,
money: true
},
],
[],

View File

@@ -27,6 +27,7 @@ import {
withBankingActions,
} from '../../withBankingActions';
import styles from './RecognizedTransactionsTable.module.scss';
import { BankAccountDataTable } from '../components/BankAccountDataTable';
interface RecognizedTransactionsTableProps extends WithBankingActionsProps {}
@@ -83,7 +84,7 @@ function RecognizedTransactionsTableRoot({
};
return (
<CashflowTransactionsTable
<BankAccountDataTable
noInitialFetch={true}
columns={columns}
data={recognizedTransactions}
@@ -100,14 +101,12 @@ function RecognizedTransactionsTableRoot({
ContextMenu={ActionsMenu}
onCellClick={handleCellClick}
// #TableVirtualizedListRows props.
vListrowHeight={'small' == 'small' ? 32 : 40}
vListrowHeight={40}
vListOverscanRowCount={0}
initialColumnsWidths={initialColumnsWidths}
onColumnResizing={handleColumnResizing}
windowScrollerProps={{ scrollElement: scrollableRef }}
noResults={<RecognizedTransactionsTableNoResults />}
className="table-constrant"
payload={{
onExclude: handleExcludeClick,
onCategorize: handleCategorizeClick,
@@ -120,45 +119,6 @@ export const RecognizedTransactionsTable = compose(withBankingActions)(
RecognizedTransactionsTableRoot,
);
const DashboardConstrantTable = styled(DataTable)`
.table {
.thead {
.th {
background: #fff;
letter-spacing: 1px;
text-transform: uppercase;
font-size: 13px;
}
}
.tbody {
.tr:last-child .td {
border-bottom: 0;
}
}
}
`;
const CashflowTransactionsTable = styled(DashboardConstrantTable)`
.table .tbody {
.tbody-inner .tr.no-results {
.td {
padding: 2rem 0;
font-size: 14px;
color: #888;
font-weight: 400;
border-bottom: 0;
}
}
.tbody-inner {
.tr .td {
border-bottom: 1px solid #e6e6e6;
}
}
}
`;
function RecognizedTransactionsTableNoResults() {
return (
<Stack spacing={12} className={styles.emptyState}>

View File

@@ -1,7 +1,9 @@
// @ts-nocheck
import React from 'react';
import clsx from 'classnames';
import { Classes } from '@blueprintjs/core';
import { Group, Icon } from '@/components';
import { getColumnWidth } from '@/utils';
import React from 'react';
import { useRecognizedTransactionsBoot } from './RecognizedTransactionsTableBoot';
const getReportColWidth = (data, accessor, headerText) => {
@@ -28,10 +30,6 @@ const recognizeAccessor = (transaction) => {
);
};
const descriptionAccessor = (transaction) => {
return <span style={{ color: '#5F6B7C' }}>{transaction.description}</span>;
};
/**
* Retrieve uncategorized transactions columns table.
*/
@@ -59,7 +57,8 @@ export function useUncategorizedTransactionsColumns() {
},
{
Header: 'Description',
accessor: descriptionAccessor,
accessor: 'description',
className: clsx(Classes.TEXT_MUTED),
textOverview: true,
},
{
@@ -82,12 +81,14 @@ export function useUncategorizedTransactionsColumns() {
accessor: 'formatted_deposit_amount',
align: 'right',
width: depositWidth,
money: true
},
{
Header: 'Withdrawal',
accessor: 'formatted_withdrawal_amount',
align: 'right',
width: withdrawalWidth,
money: true
},
],
[],

View File

@@ -1,22 +1,21 @@
// @ts-nocheck
import React from 'react';
import clsx from 'classnames';
import styled from 'styled-components';
import { Intent } from '@blueprintjs/core';
import {
DataTable,
TableFastCell,
TableSkeletonRows,
TableSkeletonHeader,
TableVirtualizedListRows,
FormattedMessage as T,
AppToaster,
} from '@/components';
import { TABLES } from '@/constants/tables';
import { ActionsMenu } from './components';
import { BankAccountDataTable } from '../components/BankAccountDataTable';
import withSettings from '@/containers/Settings/withSettings';
import { withBankingActions } from '../../withBankingActions';
import { withBanking } from '../../withBanking';
import { useMemorizedColumnsWidths } from '@/hooks';
import { useAccountUncategorizedTransactionsContext } from '../AllTransactionsUncategorizedBoot';
@@ -25,7 +24,6 @@ import { useAccountUncategorizedTransactionsColumns } from './hooks';
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { compose } from '@/utils';
import { withBanking } from '../../withBanking';
import styles from './AccountTransactionsUncategorizedTable.module.scss';
/**
@@ -48,7 +46,6 @@ function AccountTransactionsDataTable({
}) {
// Retrieve table columns.
const columns = useAccountUncategorizedTransactionsColumns();
const { scrollableRef } = useAccountTransactionsContext();
// Retrieve list context.
@@ -100,7 +97,7 @@ function AccountTransactionsDataTable({
};
return (
<CashflowTransactionsTable
<BankAccountDataTable
noInitialFetch={true}
columns={columns}
data={uncategorizedTransactions || []}
@@ -119,7 +116,7 @@ function AccountTransactionsDataTable({
ContextMenu={ActionsMenu}
onCellClick={handleCellClick}
// #TableVirtualizedListRows props.
vListrowHeight={cashflowTansactionsTableSize === 'small' ? 32 : 40}
vListrowHeight={cashflowTansactionsTableSize === 'small' ? 34 : 40}
vListOverscanRowCount={0}
initialColumnsWidths={initialColumnsWidths}
onColumnResizing={handleColumnResizing}
@@ -132,7 +129,7 @@ function AccountTransactionsDataTable({
}}
onSelectedRowsChange={handleSelectedRowsChange}
windowScrollerProps={{ scrollElement: scrollableRef }}
className={clsx('table-constrant', styles.table, {
className={clsx(styles.table, {
[styles.showCategorizeColumn]: enableMultipleCategorization,
})}
/>
@@ -151,47 +148,3 @@ export default compose(
}),
),
)(AccountTransactionsDataTable);
const DashboardConstrantTable = styled(DataTable)`
.table {
.thead {
.th {
background: #fff;
text-transform: uppercase;
letter-spacing: 1px;
font-size: 13px;i
font-weight: 500;
}
}
.tbody {
.tr:last-child .td {
border-bottom: 0;
}
}
}
`;
const CashflowTransactionsTable = styled(DashboardConstrantTable)`
.table .tbody {
.tbody-inner .tr.no-results {
.td {
padding: 2rem 0;
font-size: 14px;
color: #888;
font-weight: 400;
border-bottom: 0;
}
}
.tbody-inner {
.tr .td:not(:first-child) {
border-left: 1px solid #e6e6e6;
}
.td-description {
color: #5f6b7c;
}
}
}
`;

View File

@@ -1,8 +1,10 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import clsx from 'classnames';
import {
Checkbox,
Classes,
Intent,
PopoverInteractionKind,
Position,
@@ -97,6 +99,7 @@ export function useAccountUncategorizedTransactionsColumns() {
width: 160,
textOverview: true,
clickable: true,
className: clsx(Classes.TEXT_MUTED),
},
{
id: 'payee',
@@ -123,21 +126,21 @@ export function useAccountUncategorizedTransactionsColumns() {
id: 'deposit',
Header: intl.get('banking.label.deposit'),
accessor: 'formatted_deposit_amount',
width: 40,
className: 'deposit',
textOverview: true,
align: 'right',
width: 40,
textOverview: true,
clickable: true,
money: true
},
{
id: 'withdrawal',
Header: intl.get('banking.label.withdrawal'),
accessor: 'formatted_withdrawal_amount',
className: 'withdrawal',
width: 40,
textOverview: true,
align: 'right',
clickable: true,
money: true
},
{
id: 'categorize_include',

View File

@@ -123,6 +123,7 @@ export function useAccountTransactionsColumns() {
textOverview: true,
align: 'right',
clickable: true,
money: true,
},
{
id: 'withdrawal',
@@ -133,16 +134,18 @@ export function useAccountTransactionsColumns() {
textOverview: true,
align: 'right',
clickable: true,
money: true,
},
{
id: 'running_balance',
Header: intl.get('banking.label.running_balance'),
accessor: 'formatted_running_balance',
className: 'running_balance',
align: 'right',
width: 150,
textOverview: true,
align: 'right',
clickable: true,
money: true,
},
],
[],

View File

@@ -0,0 +1,29 @@
.root {
:global .table{
.thead {
.th {
background: #fff;
text-transform: uppercase;
letter-spacing: 1px;
font-size: 13px;
font-weight: 500;
}
}
.tbody-inner .tr.no-results {
.td {
padding: 2rem 0;
font-size: 14px;
color: #888;
font-weight: 400;
border-bottom: 0;
}
}
.tbody-inner {
.tr .td{
border-bottom: 1px solid #ececec;
}
}
}
}

View File

@@ -0,0 +1,19 @@
import clsx from 'classnames';
import { DataTable } from '@/components';
import styles from './BankAccountDataTable.module.scss';
interface BankAccountDataTableProps {
className?: string;
}
export function BankAccountDataTable({
className,
...props
}: BankAccountDataTableProps) {
return (
<DataTable
{...props}
className={clsx('table-constrant', styles.root, className)}
/>
);
}

View File

@@ -1,6 +1,7 @@
// @ts-nocheck
import React, { useMemo } from 'react';
import intl from 'react-intl-universal';
import clsx from 'classnames';
import {
Menu,
MenuItem,
@@ -14,6 +15,7 @@ import {
import { Can, Icon, Money, If, AvatarCell } from '@/components';
import { CustomerAction, AbilitySubject } from '@/constants/abilityOption';
import { safeCallback } from '@/utils';
import { CLASSES } from '@/constants';
/**
* Actions menu.
@@ -140,7 +142,7 @@ export function useCustomersTableColumns() {
id: 'company_name',
Header: intl.get('company_name'),
accessor: 'company_name',
className: 'company_name',
className: clsx('company_name', CLASSES.TEXT_MUTED),
width: 150,
clickable: true,
},
@@ -148,9 +150,9 @@ export function useCustomersTableColumns() {
id: 'work_phone',
Header: intl.get('phone_number'),
accessor: PhoneNumberAccessor,
className: 'phone_number',
width: 100,
clickable: true,
className: clsx('phone_number', CLASSES.TEXT_MUTED)
},
{
id: 'note',
@@ -159,6 +161,7 @@ export function useCustomersTableColumns() {
disableSortBy: true,
width: 85,
clickable: true,
className: clsx(CLASSES.TEXT_MUTED)
},
{
id: 'balance',
@@ -167,6 +170,7 @@ export function useCustomersTableColumns() {
align: 'right',
width: 100,
clickable: true,
money: true,
},
],
[],

View File

@@ -140,26 +140,25 @@ export function useExpensesTableColumns() {
id: 'amount',
Header: intl.get('full_amount'),
accessor: 'formatted_amount',
className: 'amount',
align: 'right',
width: 150,
clickable: true,
money: true,
className: clsx(CLASSES.FONT_BOLD),
},
{
id: 'payment_account',
Header: intl.get('payment_account'),
accessor: 'payment_account.name',
className: 'payment_account',
width: 150,
clickable: true,
className: clsx(CLASSES.TEXT_MUTED),
},
{
id: 'expense_account',
Header: intl.get('expense_account'),
accessor: ExpenseAccountAccessor,
width: 160,
className: 'expense_account',
disableSortBy: true,
clickable: true,
},

View File

@@ -41,6 +41,7 @@ const numericColumnAccessor = R.curry((data, column) => {
...column,
align: Align.Right,
width,
money: true,
};
});

View File

@@ -41,6 +41,7 @@ const numericColumnAccessor = R.curry((data, column) => {
return {
...column,
align: Align.Right,
money: true,
width,
};
});

View File

@@ -34,6 +34,7 @@ const amountAccessor = R.curry((data, column) => {
minWidth: AMOUNT_COLUMNS_MIN_WIDTH,
}),
align: Align.Right,
money: true,
};
});

View File

@@ -1,6 +1,7 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import clsx from 'classnames';
import { isNumber } from 'lodash';
import {
Menu,
@@ -11,6 +12,7 @@ import {
Position,
Button,
Popover,
Classes,
} from '@blueprintjs/core';
import { FormattedMessage as T, Icon, Money, If, Can } from '@/components';
import { isBlank, safeCallback } from '@/utils';
@@ -182,7 +184,7 @@ export const useItemsTableColumns = () => {
id: 'code',
Header: intl.get('item_code'),
accessor: 'code',
className: 'code',
className: clsx(Classes.TEXT_MUTED),
width: 120,
clickable: true,
},
@@ -198,7 +200,7 @@ export const useItemsTableColumns = () => {
id: 'category',
Header: intl.get('category'),
accessor: 'category.name',
className: 'category',
className: clsx(Classes.TEXT_MUTED),
width: 150,
clickable: true,
textOverview: true,
@@ -210,6 +212,7 @@ export const useItemsTableColumns = () => {
align: 'right',
width: 150,
clickable: true,
money: true,
},
{
id: 'cost_price',
@@ -218,6 +221,7 @@ export const useItemsTableColumns = () => {
align: 'right',
width: 150,
clickable: true,
money: true,
},
{
id: 'quantity_on_hand',
@@ -227,6 +231,7 @@ export const useItemsTableColumns = () => {
align: 'right',
width: 140,
clickable: true,
money: true,
},
],
[],

View File

@@ -189,6 +189,7 @@ export function useBillsTableColumns() {
width: 120,
align: 'right',
clickable: true,
money: true,
className: clsx(CLASSES.FONT_BOLD),
},
{

View File

@@ -207,6 +207,7 @@ export function useEstiamtesTableColumns() {
align: 'right',
clickable: true,
className: clsx(CLASSES.FONT_BOLD),
money: true
},
{
id: 'status',

View File

@@ -229,7 +229,6 @@ export function useInvoicesTableColumns() {
Header: intl.get('invoice_no__'),
accessor: 'invoice_no',
width: 100,
className: 'invoice_no',
clickable: true,
textOverview: true,
},
@@ -241,6 +240,7 @@ export function useInvoicesTableColumns() {
align: 'right',
clickable: true,
textOverview: true,
money: true,
className: clsx(CLASSES.FONT_BOLD),
},
{
@@ -266,7 +266,6 @@ export function useInvoicesTableColumns() {
Header: intl.get('reference_no'),
accessor: 'reference_no',
width: 90,
className: 'reference_no',
clickable: true,
textOverview: true,
},

View File

@@ -12,6 +12,7 @@ import {
Intent,
Classes,
} from '@blueprintjs/core';
import clsx from 'classnames';
import { Can, Icon, Money, If, AvatarCell } from '@/components';
import { VendorAction, AbilitySubject } from '@/constants/abilityOption';
@@ -163,7 +164,7 @@ export function useVendorsTableColumns() {
id: 'company_name',
Header: intl.get('company_name'),
accessor: 'company_name',
className: 'company_name',
className: clsx(Classes.TEXT_MUTED),
width: 150,
clickable: true,
},
@@ -171,7 +172,7 @@ export function useVendorsTableColumns() {
id: 'work_phone',
Header: intl.get('phone_number'),
accessor: PhoneNumberAccessor,
className: 'work_phone',
className: clsx(Classes.TEXT_MUTED),
width: 100,
clickable: true,
},
@@ -180,6 +181,7 @@ export function useVendorsTableColumns() {
Header: intl.get('note'),
accessor: NoteAccessor,
disableSortBy: true,
className: clsx(Classes.TEXT_MUTED),
width: 85,
clickable: true,
},
@@ -190,6 +192,7 @@ export function useVendorsTableColumns() {
align: 'right',
width: 100,
clickable: true,
money: true,
},
],
[],

View File

@@ -8,6 +8,7 @@
border-spacing: 0;
min-width: 100%;
display: block;
color: #101219;
.thead .thead-inner,
.tbody .tbody-inner {
@@ -21,7 +22,7 @@
padding: 0.68rem 0.5rem;
background: #f5f5f5;
font-size: 14px;
color: #4E5B6F;
color: #424853;
font-weight: 400;
border-bottom: 1px solid #d2dde2;
@@ -180,9 +181,9 @@
}
.tr .td {
border-bottom: 1px solid #e0e0e0;
border-bottom: 1px solid #ececec;
align-items: center;
color: #101219;
.placeholder {
color: #a0a0a0;
@@ -377,6 +378,8 @@
.table-constrant,
.table--constrant {
.table {
color: #000;
.thead {
.tr:first-of-type .th {
border-top: 1px solid #000000;
@@ -394,7 +397,6 @@
background: #fff;
padding: 0.5rem 0.5rem;
border-bottom: 0;
color: #000;
}
}
}