@ant-design/icons#FormOutlined TypeScript Examples
The following examples show how to use
@ant-design/icons#FormOutlined.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ActionAttribute.tsx From posthog-foss with MIT License | 6 votes |
export function ActionAttribute({ attribute, value }: { attribute: string; value?: string }): JSX.Element {
const icon =
attribute === 'text' ? (
<FontSizeOutlined />
) : attribute === 'href' ? (
<LinkOutlined />
) : attribute === 'selector' ? (
<BranchesOutlined />
) : (
<FormOutlined />
)
const text =
attribute === 'href' ? (
<a href={value} target="_blank" rel="noopener noreferrer">
{value}
</a>
) : attribute === 'selector' ? (
value ? (
<span style={{ fontFamily: 'monospace' }}>
<SelectorString value={value} />
</span>
) : (
<span>
Could not generate a unique selector for this element. Please instrument it with a unique{' '}
<code>id</code> or <code>data-attr</code> attribute.
</span>
)
) : (
value
)
return (
<div key={attribute} style={{ marginBottom: 10, paddingLeft: 24, position: 'relative' }}>
<div style={{ position: 'absolute', left: 2, top: 3, color: 'hsl(240, 14%, 50%)' }}>{icon}</div>
<span>{text}</span>
</div>
)
}
Example #2
Source File: index.tsx From memex with MIT License | 6 votes |
renderExtraOptions(id) {
return (
<div className="extra-options">
<Tooltip
title="Edit card"
onClick={() => {
this.editNote(id);
}}
>
<FormOutlined className="option-icon" />
</Tooltip>
<Tooltip title="Add to card">
<CommentOutlined className="option-icon" />
</Tooltip>
<Tooltip title="Add tags">
<TagsOutlined className="option-icon" />
</Tooltip>
<Tooltip title="Delete">
<DeleteOutlined
onClick={() => {
this.deleteNote(id);
}}
className="option-icon"
/>
</Tooltip>
</div>
);
}
Example #3
Source File: node.tsx From imove with MIT License | 5 votes |
nodeMenuConfig = [
{
key: 'copy',
title: '复制',
icon: <CopyOutlined />,
handler: shortcuts.copy.handler,
},
{
key: 'delete',
title: '删除',
icon: <DeleteOutlined />,
handler: shortcuts.delete.handler,
},
{
key: 'rename',
title: '编辑文本',
icon: <EditOutlined />,
showDividerBehind: true,
handler() {
// TODO
},
},
{
key: 'bringToTop',
title: '置于顶层',
icon: <XIcon type={'icon-bring-to-top'} />,
handler: shortcuts.bringToTop.handler,
},
{
key: 'bringToBack',
title: '置于底层',
icon: <XIcon type={'icon-bring-to-bottom'} />,
showDividerBehind: true,
handler: shortcuts.bringToBack.handler,
},
{
key: 'editCode',
title: '编辑代码',
icon: <FormOutlined />,
disabled(flowChart: Graph) {
return getSelectedNodes(flowChart).length !== 1;
},
handler(flowChart: Graph) {
flowChart.trigger('graph:editCode');
},
},
{
key: 'executeCode',
title: '执行代码',
icon: <CodeOutlined />,
disabled(flowChart: Graph) {
return getSelectedNodes(flowChart).length !== 1;
},
handler(flowChart: Graph) {
flowChart.trigger('graph:runCode');
},
},
]
Example #4
Source File: ComposeMessageModal.tsx From foodie with MIT License | 5 votes |
ComposeMessageModal: React.FC<IProps> = (props) => {
const dispatch = useDispatch();
const history = useHistory();
const clickSearchResultCallback = (user: IUser) => {
if (props.userID === user.id) return;
dispatch(initiateChat(user));
props.closeModal();
if (window.screen.width < 800) {
history.push(`/chat/${user.username}`);
}
}
return (
<Modal
isOpen={props.isOpen}
onAfterOpen={props.onAfterOpen}
onRequestClose={props.closeModal}
contentLabel="Compose Message Modal"
className="modal"
shouldCloseOnOverlayClick={true}
overlayClassName="modal-overlay"
>
<div className="relative transition-all pb-8 min-h-18rem">
<div
className="absolute right-2 top-2 p-1 rounded-full flex items-center justify-center cursor-pointer hover:bg-gray-200 dark:hover:bg-indigo-1100"
onClick={props.closeModal}
>
<CloseOutlined className="p-2 outline-none text-gray-500 dark:text-white" />
</div>
<h3 className="py-4 px-8 flex dark:text-white">
<FormOutlined className="mr-2" />
Compose Message
</h3>
<div className="flex justify-start px-8 mt-4">
<h4 className="mr-2 pt-2 dark:text-white">To: </h4>
<SearchInput
floatingResult={false}
clickItemCallback={clickSearchResultCallback}
showNoResultMessage={true}
preventDefault={true}
/>
</div>
</div>
</Modal>
);
}
Example #5
Source File: Tabs.tsx From foodie with MIT License | 5 votes |
Tabs: React.FC<IProps> = ({ username, isOwnProfile, followersCount, followingCount }) => {
const { pathname } = useLocation();
const [activeNav, setActiveNav] = useState('');
useEffect(() => {
const splitPath = pathname.split('/');
const currentNav = splitPath[splitPath.length - 1];
setActiveNav(currentNav);
}, [pathname]);
return (
<ul className="flex items-center justify-between tablet:justify-evenly flex-wrap laptop:justify-start space-x-1 laptop:space-x-4 px-4 bg-indigo-100 dark:bg-indigo-1000 laptop:dark:bg-transparent laptop:bg-transparent laptop:p-0">
<li>
<Link
to={`/user/${username}/`}
className={`${linkStyleName} ${(activeNav === username || activeNav === '') && 'border-indigo-700 dark:border-indigo-400 border-b-4 text-gray-800 dark:text-white '}`}
>
<span className="hidden laptop:inline-block">Posts</span>
<FormOutlined className="laptop:hidden text-2xl" />
</Link>
</li>
<li>
<Link
to={`/user/${username}/info`}
className={`${linkStyleName} ${activeNav === 'info' && 'border-indigo-700 dark:border-indigo-400 border-b-4'}`}
>
<span className="hidden laptop:inline-block">Info</span>
<InfoCircleOutlined className="laptop:hidden text-2xl" />
</Link>
</li>
<li>
<Link
to={`/user/${username}/followers`}
className={`${linkStyleName} ${activeNav === 'followers' && 'border-indigo-700 dark:border-indigo-400 border-b-4'}`}
>
<span className="laptop:text-lg text-indigo-700 dark:text-indigo-400">{followersCount}</span>
<span className="hidden laptop:inline-block">{followersCount > 1 ? 'Followers' : 'Follower'}</span>
<TeamOutlined className="laptop:hidden text-2xl" />
</Link>
</li>
<li>
<Link
to={`/user/${username}/following`}
className={`${linkStyleName} ${activeNav === 'following' && 'border-indigo-700 dark:border-indigo-400 border-b-4'}`}
>
<span className="laptop:text-lg text-indigo-700 dark:text-indigo-400">{followingCount}</span>
<span className="hidden laptop:inline-block">Following</span>
<UserAddOutlined className="laptop:hidden text-2xl" />
</Link>
</li>
{isOwnProfile && (
<li>
<Link
to={`/user/${username}/bookmarks`}
className={`${linkStyleName} ${activeNav === 'bookmarks' && 'border-indigo-700 dark:border-indigo-400 border-b-4'}`}
>
<span className="hidden laptop:inline-block">Bookmarks</span>
<StarOutlined className="laptop:hidden text-2xl" />
</Link>
</li>
)}
</ul>
);
}
Example #6
Source File: ChartDataViewPanel.tsx From datart with Apache License 2.0 | 4 votes |
ChartDataViewPanel: FC<{
dataView?: ChartDataView;
defaultViewId?: string;
chartConfig?: ChartConfig;
onDataViewChange?: () => void;
}> = memo(({ dataView, defaultViewId, chartConfig, onDataViewChange }) => {
const t = useI18NPrefix(`viz.workbench.dataview`);
const dispatch = useDispatch();
const dataviewTreeSelector = useMemo(makeDataviewTreeSelector, []);
const getSelectable = useCallback(v => !v.isFolder, []);
const dataviewTreeData = useSelector(state =>
dataviewTreeSelector(state, getSelectable),
);
const [showModal, modalContextHolder] = useStateModal({});
const [isDisplayAddNewModal, setIsDisplayAddNewModal] = useToggle();
const views = useSelector(dataviewsSelector);
const path = useMemo(() => {
return views?.length && dataView
? getPath(
views as Array<{ id: string; parentId: string }>,
{ id: dataView.id, parentId: dataView.parentId },
ResourceTypes.View,
)
: [];
}, [views, dataView]);
const managePermission = useCascadeAccess({
module: ResourceTypes.View,
path,
level: PermissionLevels.Manage,
});
const allowManage = managePermission(true);
const allowEnableView = useAccess({
type: 'module',
module: ResourceTypes.View,
id: '',
level: PermissionLevels.Enable,
})(true);
const history = useHistory();
const handleDataViewChange = useCallback(
value => {
if (dataView?.id === value) {
return false;
}
let Data = chartConfig?.datas?.filter(v => v.rows && v.rows.length);
if (Data?.length) {
(showModal as Function)({
title: '',
modalSize: StateModalSize.XSMALL,
content: () => t('toggleViewTip'),
onOk: () => {
onDataViewChange?.();
dispatch(fetchViewDetailAction(value));
},
});
} else {
onDataViewChange?.();
dispatch(fetchViewDetailAction(value));
}
},
[
chartConfig?.datas,
dataView?.id,
dispatch,
onDataViewChange,
showModal,
t,
],
);
const filterDateViewTreeNode = useCallback(
(inputValue, node) =>
node.title.toLowerCase().includes(inputValue.toLowerCase()),
[],
);
const handleAddNewOrUpdateComputedField = async (
field?: ChartDataViewMeta,
originId?: string,
) => {
if (!field) {
return Promise.reject('field is empty');
}
let validComputedField = true;
try {
validComputedField = await checkComputedFieldAsync(
dataView?.sourceId,
field.expression,
);
} catch (error) {
validComputedField = false;
}
if (!validComputedField) {
message.error('validate function computed field failed');
return Promise.reject('validate function computed field failed');
}
const otherComputedFields = dataView?.computedFields?.filter(
f => f.id !== originId,
);
const isNameConflict = !!otherComputedFields?.find(f => f.id === field?.id);
if (isNameConflict) {
message.error(
'The computed field has already been exist, please choose anohter one!',
);
return Promise.reject(
'The computed field has already been exist, please choose anohter one!',
);
}
const currentFieldIndex = (dataView?.computedFields || []).findIndex(
f => f.id === originId,
);
if (currentFieldIndex >= 0) {
const newComputedFields = updateByKey(
dataView?.computedFields,
currentFieldIndex,
field,
);
dispatch(
workbenchSlice.actions.updateCurrentDataViewComputedFields(
newComputedFields!,
),
);
return;
}
const newComputedFields = (dataView?.computedFields || []).concat([field]);
dispatch(
workbenchSlice.actions.updateCurrentDataViewComputedFields(
newComputedFields,
),
);
};
const handleDeleteComputedField = fieldId => {
const newComputedFields = (dataView?.computedFields || []).filter(
f => f.id !== fieldId,
);
dispatch(
workbenchSlice.actions.updateCurrentDataViewComputedFields(
newComputedFields,
),
);
};
const handleEditComputedField = fieldId => {
const editField = (dataView?.computedFields || []).find(
f => f.id === fieldId,
);
handleAddOrEditComputedField(editField);
};
const handleAddOrEditComputedField = field => {
(showModal as Function)({
title: t('createComputedFields'),
modalSize: StateModalSize.MIDDLE,
content: onChange => (
<ChartComputedFieldSettingPanel
computedField={field}
sourceId={dataView?.sourceId}
fields={dataView?.meta}
variables={dataView?.meta?.filter(
c => c.category === ChartDataViewFieldCategory.Variable,
)}
allComputedFields={dataView?.computedFields}
onChange={onChange}
/>
),
onOk: newField => handleAddNewOrUpdateComputedField(newField, field?.id),
});
};
const sortedMetaFields = useMemo(() => {
const computedFields = dataView?.computedFields?.filter(
v => v.category !== ChartDataViewFieldCategory.DateLevelComputedField,
);
const allFields = (dataView?.meta || []).concat(computedFields || []);
const hierarchyFields = allFields.filter(
f => f.role === ColumnRole.Hierarchy,
);
const allNonHierarchyFields = allFields.filter(
f => f.role !== ColumnRole.Hierarchy,
);
const stringFields = allNonHierarchyFields.filter(
f => f.type === DataViewFieldType.STRING,
);
const numericFields = allNonHierarchyFields.filter(
f => f.type === DataViewFieldType.NUMERIC,
);
const dateFields = allNonHierarchyFields.filter(
f => f.type === DataViewFieldType.DATE,
);
return [
...hierarchyFields,
...dateFields,
...stringFields,
...numericFields,
];
}, [dataView?.meta, dataView?.computedFields]);
const editView = useCallback(() => {
let orgId = dataView?.orgId as string;
let viewId = dataView?.id as string;
history.push(`/organizations/${orgId}/views/${viewId}`);
}, [dataView?.id, dataView?.orgId, history]);
const handleConfirmVisible = useCallback(() => {
(showModal as Function)({
title: '',
modalSize: StateModalSize.XSMALL,
content: () => t('editViewTip'),
onOk: editView,
});
}, [editView, showModal, t]);
useMount(() => {
if (defaultViewId) {
handleDataViewChange(defaultViewId);
}
});
return (
<StyledChartDataViewPanel>
<Header>
<Tooltip placement="topLeft" title={t('editView')}>
<ToolbarButton
disabled={!(allowEnableView && allowManage && dataView)}
iconSize={14}
icon={<FormOutlined />}
size="small"
onClick={handleConfirmVisible}
/>
</Tooltip>
<TreeSelect
showSearch
placeholder={t('plsSelectDataView')}
className="view-selector"
treeData={dataviewTreeData}
value={dataView?.id}
onChange={handleDataViewChange}
filterTreeNode={filterDateViewTreeNode}
bordered={false}
/>
<Popover
placement="bottomRight"
visible={isDisplayAddNewModal}
onVisibleChange={() => setIsDisplayAddNewModal()}
trigger="click"
content={
<ul>
<li
onClick={() => {
setIsDisplayAddNewModal();
handleAddOrEditComputedField(null);
}}
>
{t('createComputedFields')}
</li>
{/* <li>{t('createVariableFields')}</li> */}
</ul>
}
>
<ToolbarButton icon={<PlusOutlined />} size="small" />
</Popover>
{modalContextHolder}
</Header>
<ChartDraggableSourceGroupContainer
meta={sortedMetaFields}
onDeleteComputedField={handleDeleteComputedField}
onEditComputedField={handleEditComputedField}
/>
</StyledChartDataViewPanel>
);
})
Example #7
Source File: index.tsx From anew-server with MIT License | 4 votes |
UserList: React.FC = () => {
const [createVisible, setCreateVisible] = useState<boolean>(false);
const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [formValues, setFormValues] = useState<API.UserList>();
const access = useAccess();
const handleDelete = (record: API.Ids) => {
if (!record) return;
if (Array.isArray(record.ids) && !record.ids.length) return;
const content = `您是否要删除这${Array.isArray(record.ids) ? record.ids.length : ''}项?`;
Modal.confirm({
title: '注意',
content,
onOk: () => {
deleteUser(record).then((res) => {
if (res.code === 200 && res.status === true) {
message.success(res.message);
if (actionRef.current) {
actionRef.current.reload();
}
}
});
},
onCancel() { },
});
};
const columns: ProColumns<API.UserList>[] = [
{
title: '用户名',
dataIndex: 'username',
},
{
title: '姓名',
dataIndex: 'name',
},
{
title: '手机',
dataIndex: 'mobile',
},
{
title: '邮箱',
dataIndex: 'email',
search: false,
},
{
title: '角色',
dataIndex: 'role',
search: false,
render: (_, record: API.UserList) => {
return record.role.name;
},
},
{
title: '部门',
dataIndex: 'dept',
search: false,
render: (_, record: API.UserList) => {
return record.dept.name;
},
},
{
title: '创建人',
dataIndex: 'creator',
},
{
title: '状态',
dataIndex: 'status',
valueEnum: {
true: {
text: '激活',
status: 'Processing',
},
false: {
text: '禁用',
status: 'Error',
},
},
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record: API.UserList) => (
<>
<Access accessible={access.hasPerms(['admin', 'user:update'])}>
<Tooltip title="修改">
<FormOutlined
style={{ fontSize: '17px', color: '#52c41a' }}
onClick={() => {
setFormValues(record);
setUpdateVisible(true);
}}
/>
</Tooltip>
</Access>
<Divider type="vertical" />
<Access accessible={access.hasPerms(['admin', 'user:delete'])}>
<Tooltip title="删除">
<DeleteOutlined
style={{ fontSize: '17px', color: 'red' }}
onClick={() => handleDelete({ ids: [record.id] })}
/>
</Tooltip>
</Access>
</>
),
},
];
return (
<PageHeaderWrapper>
{/* 权限控制显示内容 */}
{access.hasPerms(['admin', 'user:list']) && <ProTable
actionRef={actionRef}
rowKey="id"
toolBarRender={(action, { selectedRows }) => [
<Access accessible={access.hasPerms(['admin', 'user:create'])}>
<Button key="1" type="primary" onClick={() => setCreateVisible(true)}>
<PlusOutlined /> 新建
</Button>
</Access>,
selectedRows && selectedRows.length > 0 && (
<Access accessible={access.hasPerms(['admin', 'user:delete'])}>
<Button
key="2"
type="primary"
onClick={() => handleDelete({ ids: selectedRows.map((item) => item.id) })}
danger
>
<DeleteOutlined /> 删除
</Button>
</Access>
),
]}
tableAlertRender={({ selectedRowKeys, selectedRows }) => (
<div>
已选择{' '}
<a
style={{
fontWeight: 600,
}}
>
{selectedRowKeys.length}
</a>{' '}
项
</div>
)}
request={async (params) => queryUsers({ params }).then((res) => res.data)}
columns={columns}
rowSelection={{}}
/>}
{createVisible && (
<CreateForm
actionRef={actionRef}
handleChange={setCreateVisible}
modalVisible={createVisible}
/>
)}
{updateVisible && (
<UpdateForm
actionRef={actionRef}
handleChange={setUpdateVisible}
modalVisible={updateVisible}
values={formValues}
/>
)}
</PageHeaderWrapper>
);
}
Example #8
Source File: index.tsx From anew-server with MIT License | 4 votes |
RoleList: React.FC = () => {
const [createVisible, setCreateVisible] = useState<boolean>(false);
const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const [permsVisible, setPermsVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [formValues, setFormValues] = useState<API.RoleList>();
const access = useAccess();
const handleDelete = (record: API.Ids) => {
if (!record) return;
if (Array.isArray(record.ids) && !record.ids.length) return;
const content = `您是否要删除这${Array.isArray(record.ids) ? record.ids.length : ''}项?`;
Modal.confirm({
title: '注意',
content,
onOk: () => {
deleteRole(record).then((res) => {
if (res.code === 200 && res.status === true) {
message.success(res.message);
if (actionRef.current) {
actionRef.current.reload();
}
}
});
},
onCancel() { },
});
};
const columns: ProColumns<API.RoleList>[] = [
{
title: '名称',
dataIndex: 'name',
},
{
title: '关键字',
dataIndex: 'keyword',
search: false,
},
{
title: '说明',
dataIndex: 'desc',
},
{
title: '创建人',
dataIndex: 'creator',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => (
<>
<Access accessible={access.hasPerms(['admin', 'role:update:perms'])}>
<Tooltip title="设置权限">
<SafetyCertificateOutlined
style={{ fontSize: '17px', color: 'blue' }}
onClick={() => {
if (record.keyword != 'admin') {
setFormValues(record);
setPermsVisible(true);
} else {
message.info("管理员拥有所有权限");
}
}}
/>
</Tooltip>
</Access>
<Divider type="vertical" />
<Access accessible={access.hasPerms(['admin', 'role:update'])}>
<Tooltip title="修改">
<FormOutlined
style={{ fontSize: '17px', color: '#52c41a' }}
onClick={() => {
setFormValues(record);
setUpdateVisible(true);
}}
/>
</Tooltip>
</Access>
<Divider type="vertical" />
<Access accessible={access.hasPerms(['admin', 'role:delete'])}>
<Tooltip title="删除">
<DeleteOutlined
style={{ fontSize: '17px', color: 'red' }}
onClick={() => handleDelete({ ids: [record.id] })}
/>
</Tooltip>
</Access>
</>
),
},
];
return (
<PageHeaderWrapper>
{/* 权限控制显示内容 */}
{access.hasPerms(['admin', 'role:list']) && <ProTable
actionRef={actionRef}
rowKey="id"
toolBarRender={(action, { selectedRows }) => [
<Access accessible={access.hasPerms(['admin', 'role:create'])}>
<Button key="1" type="primary" onClick={() => setCreateVisible(true)}>
<PlusOutlined /> 新建
</Button>
</Access>,
selectedRows && selectedRows.length > 0 && (
<Access accessible={access.hasPerms(['admin', 'role:delete'])}>
<Button
key="2"
type="primary"
onClick={() => handleDelete({ ids: selectedRows.map((item) => item.id) })}
danger
>
<DeleteOutlined /> 删除
</Button>
</Access>
),
]}
tableAlertRender={({ selectedRowKeys, selectedRows }) => (
<div>
已选择{' '}
<a
style={{
fontWeight: 600,
}}
>
{selectedRowKeys.length}
</a>{' '}
项
</div>
)}
request={async (params) => queryRoles({ params }).then((res) => res.data)}
columns={columns}
rowSelection={{}}
/>}
{createVisible && (
<CreateForm
actionRef={actionRef}
handleChange={setCreateVisible}
modalVisible={createVisible}
/>
)}
{updateVisible && (
<UpdateForm
actionRef={actionRef}
handleChange={setUpdateVisible}
modalVisible={updateVisible}
values={formValues}
/>
)}
{permsVisible && (
<PermsForm
actionRef={actionRef}
handleChange={setPermsVisible}
modalVisible={permsVisible}
values={formValues}
/>
)}
</PageHeaderWrapper>
);
}
Example #9
Source File: index.tsx From anew-server with MIT License | 4 votes |
MenuList: React.FC = () => {
const [createVisible, setCreateVisible] = useState<boolean>(false);
const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [formValues, setFormValues] = useState<API.MenuList>();
const access = useAccess();
const handleDelete = (record: API.Ids) => {
if (!record) return;
if (Array.isArray(record.ids) && !record.ids.length) return;
const content = `您是否要删除这${Array.isArray(record.ids) ? record.ids.length : ''}项?`;
Modal.confirm({
title: '注意',
content,
onOk: () => {
deleteMenu(record).then((res) => {
if (res.code === 200 && res.status === true) {
message.success(res.message);
if (actionRef.current) {
actionRef.current.reload();
}
}
});
},
onCancel() { },
});
};
const columns: ProColumns<API.MenuList>[] = [
{
title: '名称',
dataIndex: 'name',
search: false,
},
{
title: '图标',
dataIndex: 'icon',
search: false,
},
{
title: '路径',
dataIndex: 'path',
search: false,
},
{
title: '排序',
dataIndex: 'sort',
search: false,
},
{
title: '创建人',
dataIndex: 'creator',
search: false,
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record: API.MenuList) => (
<>
<Access accessible={access.hasPerms(['admin', 'menu:update'])}>
<Tooltip title="修改">
<FormOutlined
style={{ fontSize: '17px', color: '#52c41a' }}
onClick={() => {
setFormValues(record);
setUpdateVisible(true);
}}
/>
</Tooltip>
</Access>
<Divider type="vertical" />
<Access accessible={access.hasPerms(['admin', 'menu:delete'])}>
<Tooltip title="删除">
<DeleteOutlined
style={{ fontSize: '17px', color: 'red' }}
onClick={() => handleDelete({ ids: [record.id] })}
/>
</Tooltip>
</Access>
</>
),
},
];
return (
<PageHeaderWrapper>
{/* 权限控制显示内容 */}
{access.hasPerms(['admin', 'menu:list']) && <ProTable
actionRef={actionRef}
rowKey="id"
pagination={false}
search={false}
toolBarRender={(action, { selectedRows }) => [
<Access accessible={access.hasPerms(['admin', 'menu:create'])}>
<Button key="1" type="primary" onClick={() => setCreateVisible(true)}>
<PlusOutlined /> 新建
</Button>
</Access>,
selectedRows && selectedRows.length > 0 && (
<Access accessible={access.hasPerms(['admin', 'menu:delete'])}>
<Button
key="2"
type="primary"
onClick={() => handleDelete({ ids: selectedRows.map((item) => item.id) })}
danger
>
<DeleteOutlined /> 删除
</Button>
</Access>
),
]}
tableAlertRender={({ selectedRowKeys, selectedRows }) => (
<div>
已选择{' '}
<a
style={{
fontWeight: 600,
}}
>
{selectedRowKeys.length}
</a>{' '}
项
</div>
)}
request={async (params) => queryMenus({ ...params })}
columns={columns}
rowSelection={{}}
/>}
{createVisible && (
<CreateForm
actionRef={actionRef}
handleChange={setCreateVisible}
modalVisible={createVisible}
/>
)}
{updateVisible && (
<UpdateForm
actionRef={actionRef}
handleChange={setUpdateVisible}
modalVisible={updateVisible}
values={formValues}
/>
)}
</PageHeaderWrapper>
);
}
Example #10
Source File: index.tsx From anew-server with MIT License | 4 votes |
DictList: React.FC = () => {
const [createVisible, setCreateVisible] = useState<boolean>(false);
const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [formValues, setFormValues] = useState<API.DictList>();
const access = useAccess();
const handleDelete = (record: API.Ids) => {
if (!record) return;
if (Array.isArray(record.ids) && !record.ids.length) return;
const content = `您是否要删除这${Array.isArray(record.ids) ? record.ids.length : ''}项?`;
Modal.confirm({
title: '注意',
content,
onOk: () => {
deleteDict(record).then((res) => {
if (res.code === 200 && res.status === true) {
message.success(res.message);
if (actionRef.current) {
actionRef.current.reload();
}
}
});
},
onCancel() { },
});
};
const columns: ProColumns<API.DictList>[] = [
{
title: '字典标签',
dataIndex: 'dict_key',
},
{
title: '字典键值',
dataIndex: 'dict_value',
},
{
title: '详情',
dataIndex: 'desc',
search: false,
},
{
title: '排序',
dataIndex: 'sort',
search: false,
},
{
title: '创建人',
dataIndex: 'creator',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record: API.DictList) => (
<>
<Access accessible={access.hasPerms(['admin', 'dict:update'])}>
<Tooltip title="修改">
<FormOutlined
style={{ fontSize: '17px', color: '#52c41a' }}
onClick={() => {
setFormValues(record);
setUpdateVisible(true);
}}
/>
</Tooltip>
</Access>
<Divider type="vertical" />
<Access accessible={access.hasPerms(['admin', 'dict:delete'])}>
<Tooltip title="删除">
<DeleteOutlined
style={{ fontSize: '17px', color: 'red' }}
onClick={() => handleDelete({ ids: [record.id] })}
/>
</Tooltip>
</Access>
</>
),
},
];
return (
<PageHeaderWrapper>
{/* 权限控制显示内容 */}
{access.hasPerms(['admin', 'dict:list']) && <ProTable
actionRef={actionRef}
rowKey="id"
pagination={false}
toolBarRender={(action, { selectedRows }) => [
<Access accessible={access.hasPerms(['admin', 'dict:create'])}>
<Button key="1" type="primary" onClick={() => setCreateVisible(true)}>
<PlusOutlined /> 新建
</Button>
</Access>,
selectedRows && selectedRows.length > 0 && (
<Access accessible={access.hasPerms(['admin', 'dict:delete'])}>
<Button
key="2"
type="primary"
onClick={() => handleDelete({ ids: selectedRows.map((item) => item.id) })}
danger
>
<DeleteOutlined /> 删除
</Button>
</Access>
),
]}
tableAlertRender={({ selectedRowKeys, selectedRows }) => (
<div>
已选择{' '}
<a
style={{
fontWeight: 600,
}}
>
{selectedRowKeys.length}
</a>{' '}
项
</div>
)}
request={async (params) => queryDicts({ ...params })}
columns={columns}
rowSelection={{}}
/>}
{createVisible && (
<CreateForm
actionRef={actionRef}
handleChange={setCreateVisible}
modalVisible={createVisible}
/>
)}
{updateVisible && (
<UpdateForm
actionRef={actionRef}
handleChange={setUpdateVisible}
modalVisible={updateVisible}
values={formValues}
/>
)}
</PageHeaderWrapper>
);
}
Example #11
Source File: index.tsx From anew-server with MIT License | 4 votes |
DeptList: React.FC = () => {
const [createVisible, setCreateVisible] = useState<boolean>(false);
const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [formValues, setFormValues] = useState<API.DeptList>();
const access = useAccess();
const handleDelete = (record: API.Ids) => {
if (!record) return;
if (Array.isArray(record.ids) && !record.ids.length) return;
const content = `您是否要删除这${Array.isArray(record.ids) ? record.ids.length : ''}项?`;
Modal.confirm({
title: '注意',
content,
onOk: () => {
deleteDept(record).then((res) => {
if (res.code === 200 && res.status === true) {
message.success(res.message);
if (actionRef.current) {
actionRef.current.reload();
}
}
});
},
onCancel() { },
});
};
const columns: ProColumns<API.DeptList>[] = [
{
title: '名称',
dataIndex: 'name',
},
{
title: '排序',
dataIndex: 'sort',
search: false,
},
{
title: '创建人',
dataIndex: 'creator',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record: API.DeptList) => (
<>
<Access accessible={access.hasPerms(['admin', 'dept:update'])}>
<Tooltip title="修改">
<FormOutlined
style={{ fontSize: '17px', color: '#52c41a' }}
onClick={() => {
setFormValues(record);
setUpdateVisible(true);
}}
/>
</Tooltip>
</Access>
<Divider type="vertical" />
<Access accessible={access.hasPerms(['admin', 'dept:delete'])}>
<Tooltip title="删除">
<DeleteOutlined
style={{ fontSize: '17px', color: 'red' }}
onClick={() => handleDelete({ ids: [record.id] })}
/>
</Tooltip>
</Access>
</>
),
},
];
return (
<PageHeaderWrapper>
{/* 权限控制显示内容 */}
{access.hasPerms(['admin', 'dept:list']) && <ProTable
actionRef={actionRef}
rowKey="id"
pagination={false}
toolBarRender={(action, { selectedRows }) => [
<Access accessible={access.hasPerms(['admin', 'dept:create'])}>
<Button key="1" type="primary" onClick={() => setCreateVisible(true)}>
<PlusOutlined /> 新建
</Button>
</Access>,
selectedRows && selectedRows.length > 0 && (
<Access accessible={access.hasPerms(['admin', 'dept:delete'])}>
<Button
key="2"
type="primary"
onClick={() => handleDelete({ ids: selectedRows.map((item) => item.id) })}
danger
>
<DeleteOutlined /> 删除
</Button>
</Access>
),
]}
tableAlertRender={({ selectedRowKeys, selectedRows }) => (
<div>
已选择{' '}
<a
style={{
fontWeight: 600,
}}
>
{selectedRowKeys.length}
</a>{' '}
项
</div>
)}
request={async (params) => queryDepts({ ...params })}
columns={columns}
rowSelection={{}}
/>}
{createVisible && (
<CreateForm
actionRef={actionRef}
handleChange={setCreateVisible}
modalVisible={createVisible}
/>
)}
{updateVisible && (
<UpdateForm
actionRef={actionRef}
handleChange={setUpdateVisible}
modalVisible={updateVisible}
values={formValues}
/>
)}
</PageHeaderWrapper>
);
}
Example #12
Source File: index.tsx From anew-server with MIT License | 4 votes |
ApiList: React.FC = () => {
const [createVisible, setCreateVisible] = useState<boolean>(false);
const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [formValues, setFormValues] = useState<API.ApiList>();
const access = useAccess();
const handleDelete = (record: API.Ids) => {
if (!record) return;
if (Array.isArray(record.ids) && !record.ids.length) return;
const content = `您是否要删除这${Array.isArray(record.ids) ? record.ids.length : ''}项?`;
Modal.confirm({
title: '注意',
content,
onOk: () => {
deleteApi(record).then((res) => {
if (res.code === 200 && res.status === true) {
message.success(res.message);
if (actionRef.current) {
actionRef.current.reload();
}
}
});
},
onCancel() { },
});
};
const columns: ProColumns<API.ApiList>[] = [
{
title: '名称',
dataIndex: 'name',
},
{
title: '请求方式',
dataIndex: 'method',
// render: (_, row) => {
// let color = 'blue';
// if (row.method == 'POST') {
// color = 'gold';
// } else if (row.method == 'PATCH') {
// color = 'lime';
// } else if (row.method == 'PUT') {
// color = 'green';
// } else if (row.method == 'DELETE') {
// color = 'red';
// }
// return <Tag color={color}>{row.method}</Tag>;
// },
},
{
title: '访问路径',
dataIndex: 'path',
},
{
title: '权限标识',
dataIndex: 'perms_tag',
},
{
title: '说明',
dataIndex: 'desc',
search: false,
},
{
title: '创建人',
dataIndex: 'creator',
search: false,
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record: API.ApiList) => (
<>
<Access accessible={access.hasPerms(['admin', 'api:update'])}>
<Tooltip title="修改">
<FormOutlined
style={{ fontSize: '17px', color: '#52c41a' }}
onClick={() => {
setFormValues(record);
setUpdateVisible(true);
}}
/>
</Tooltip>
</Access>
<Divider type="vertical" />
<Access accessible={access.hasPerms(['admin', 'api:delete'])}>
<Tooltip title="删除">
<DeleteOutlined
style={{ fontSize: '17px', color: 'red' }}
onClick={() => handleDelete({ ids: [record.id] })}
/>
</Tooltip>
</Access>
</>
),
},
];
return (
<PageHeaderWrapper>
{/* 权限控制显示内容 */}
{access.hasPerms(['admin', 'api:list']) && <ProTable
actionRef={actionRef}
rowKey="id"
pagination={false}
search={false}
toolBarRender={(action, { selectedRows }) => [
<Access accessible={access.hasPerms(['admin', 'api:create'])}>
<Button key="1" type="primary" onClick={() => setCreateVisible(true)}>
<PlusOutlined /> 新建
</Button>
</Access>,
selectedRows && selectedRows.length > 0 && (
<Access accessible={access.hasPerms(['admin', 'api:delete'])}>
<Button
key="2"
type="primary"
onClick={() => handleDelete({ ids: selectedRows.map((item) => item.id) })}
danger
>
<DeleteOutlined /> 删除
</Button>
</Access>
),
]}
tableAlertRender={({ selectedRowKeys, selectedRows }) => (
<div>
已选择{' '}
<a
style={{
fontWeight: 600,
}}
>
{selectedRowKeys.length}
</a>{' '}
项
</div>
)}
request={async (params) => queryApis({ ...params })}
columns={columns}
rowSelection={{}}
/>}
{createVisible && (
<CreateForm
actionRef={actionRef}
handleChange={setCreateVisible}
modalVisible={createVisible}
/>
)}
{updateVisible && (
<UpdateForm
actionRef={actionRef}
handleChange={setUpdateVisible}
modalVisible={updateVisible}
values={formValues}
/>
)}
</PageHeaderWrapper>
);
}
Example #13
Source File: index.tsx From anew-server with MIT License | 4 votes |
HostGroupList: React.FC = () => {
const [createVisible, setCreateVisible] = useState<boolean>(false);
const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [formValues, setFormValues] = useState<API.HostGroupList>();
const access = useAccess();
const handleDelete = (record: API.Ids) => {
if (!record) return;
if (Array.isArray(record.ids) && !record.ids.length) return;
const content = `您是否要删除这${Array.isArray(record.ids) ? record.ids.length : ''}项?`;
Modal.confirm({
title: '注意',
content,
onOk: () => {
deleteHostGroup(record).then((res) => {
if (res.code === 200 && res.status === true) {
message.success(res.message);
if (actionRef.current) {
actionRef.current.reload();
}
}
});
},
onCancel() { },
});
};
const columns: ProColumns<API.HostGroupList>[] = [
{
title: '名称',
dataIndex: 'name',
},
{
title: '说明',
dataIndex: 'desc',
search: false,
},
{
title: '创建人',
dataIndex: 'creator',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => (
<>
<Divider type="vertical" />
<Tooltip title="修改">
<FormOutlined
style={{ fontSize: '17px', color: '#52c41a' }}
onClick={() => {
setFormValues(record);
setUpdateVisible(true);
}}
/>
</Tooltip>
<Divider type="vertical" />
<Tooltip title="删除">
<DeleteOutlined
style={{ fontSize: '17px', color: 'red' }}
onClick={() => handleDelete({ ids: [record.id] })}
/>
</Tooltip>
</>
),
},
];
return (
<PageHeaderWrapper>
{/* 权限控制显示内容 */}
{access.hasPerms(['admin', 'host:group:list']) && <ProTable
actionRef={actionRef}
rowKey="id"
toolBarRender={(action, { selectedRows }) => [
<Access accessible={access.hasPerms(['admin', 'host:group:create'])}>
<Button key="1" type="primary" onClick={() => setCreateVisible(true)}>
<PlusOutlined /> 新建
</Button>
</Access>,
selectedRows && selectedRows.length > 0 && (
<Access accessible={access.hasPerms(['admin', 'host:group:delete'])}>
<Button
key="2"
type="primary"
onClick={() => handleDelete({ ids: selectedRows.map((item) => item.id) })}
danger
>
<DeleteOutlined /> 删除
</Button>
</Access>
),
]}
tableAlertRender={({ selectedRowKeys, selectedRows }) => (
<div>
已选择{' '}
<a
style={{
fontWeight: 600,
}}
>
{selectedRowKeys.length}
</a>{' '}
项
</div>
)}
request={async (params) => queryHostGroups({ params }).then((res) => res.data)}
columns={columns}
rowSelection={{}}
/>}
{createVisible && (
<CreateForm
actionRef={actionRef}
handleChange={setCreateVisible}
modalVisible={createVisible}
/>
)}
{updateVisible && (
<UpdateForm
actionRef={actionRef}
handleChange={setUpdateVisible}
modalVisible={updateVisible}
values={formValues}
/>
)}
</PageHeaderWrapper>
);
}
Example #14
Source File: index.tsx From datart with Apache License 2.0 | 4 votes |
export function Navbar() {
const { actions } = useMainSlice();
const [profileVisible, setProfileVisible] = useState(false);
const [modifyPasswordVisible, setModifyPasswordVisible] = useState(false);
const dispatch = useDispatch();
const history = useHistory();
const { i18n } = useTranslation();
const systemInfo = useSelector(selectSystemInfo);
const orgId = useSelector(selectOrgId);
const currentOrganization = useSelector(selectCurrentOrganization);
const loggedInUser = useSelector(selectLoggedInUser);
const organizationListLoading = useSelector(selectOrganizationListLoading);
const downloadPolling = useSelector(selectDownloadPolling);
const themeKey = useSelector(selectThemeKey);
const matchModules = useRouteMatch<{ moduleName: string }>(
'/organizations/:orgId/:moduleName',
);
const t = useI18NPrefix('main');
const brandClick = useCallback(() => {
history.push('/');
}, [history]);
const hideProfile = useCallback(() => {
setProfileVisible(false);
}, []);
const hideModifyPassword = useCallback(() => {
setModifyPasswordVisible(false);
}, []);
const organizationListVisibleChange = useCallback(
visible => {
if (visible && !organizationListLoading) {
dispatch(getOrganizations());
}
},
[dispatch, organizationListLoading],
);
const subNavs = useMemo(
() => [
{
name: 'variables',
title: t('subNavs.variables.title'),
icon: <FunctionOutlined />,
module: ResourceTypes.Manager,
},
{
name: 'orgSettings',
title: t('subNavs.orgSettings.title'),
icon: <SettingOutlined />,
module: ResourceTypes.Manager,
},
],
[t],
);
const navs = useMemo(
() => [
{
name: 'vizs',
title: t('nav.vizs'),
icon: <i className="iconfont icon-xietongzhihuidaping" />,
module: ResourceTypes.Viz,
},
{
name: 'views',
title: t('nav.views'),
icon: <i className="iconfont icon-24gf-table" />,
module: ResourceTypes.View,
},
{
name: 'sources',
title: t('nav.sources'),
icon: <i className="iconfont icon-shujukupeizhi" />,
module: ResourceTypes.Source,
},
{
name: 'schedules',
title: t('nav.schedules'),
icon: <i className="iconfont icon-fasongyoujian" />,
module: ResourceTypes.Schedule,
},
{
name: 'members',
title: t('nav.members'),
icon: <i className="iconfont icon-users1" />,
isActive: (_, location) =>
!!location.pathname.match(
/\/organizations\/[\w]{32}\/(members|roles)/,
),
module: ResourceTypes.User,
},
{
name: 'permissions',
title: t('nav.permissions'),
icon: <SafetyCertificateFilled />,
module: ResourceTypes.Manager,
},
{
name: 'toSub',
title: t('nav.settings'),
icon: <SettingFilled />,
isActive: (_, location) => {
const reg = new RegExp(
`\\/organizations\\/[\\w]{32}\\/(${subNavs
.map(({ name }) => name)
.join('|')})`,
);
return !!location.pathname.match(reg);
},
module: ResourceTypes.Manager,
},
],
[subNavs, t],
);
const showSubNav = useMemo(
() => subNavs.some(({ name }) => name === matchModules?.params.moduleName),
[matchModules?.params.moduleName, subNavs],
);
const handleChangeThemeFn = useCallback(
(theme: ThemeKeyType) => {
if (themeKey !== theme) {
dispatch(themeSlice.actions.changeTheme(theme));
changeAntdTheme(theme);
saveTheme(theme);
}
},
[dispatch, themeKey],
);
const userMenuSelect = useCallback(
({ key }) => {
switch (key) {
case 'profile':
setProfileVisible(true);
break;
case 'logout':
dispatch(
logout(() => {
history.replace('/');
}),
);
break;
case 'password':
setModifyPasswordVisible(true);
break;
case 'zh':
case 'en':
if (i18n.language !== key) {
changeLang(key);
}
break;
case 'dark':
case 'light':
handleChangeThemeFn(key);
break;
default:
break;
}
},
[dispatch, history, i18n, handleChangeThemeFn],
);
const onSetPolling = useCallback(
(polling: boolean) => {
dispatch(actions.setDownloadPolling(polling));
},
[dispatch, actions],
);
return (
<>
<MainNav>
<Brand onClick={brandClick}>
<img src={logo} alt="logo" />
</Brand>
<Nav>
{navs.map(({ name, title, icon, isActive, module }) => {
return name !== 'toSub' || subNavs.length > 0 ? (
<Access
key={name}
type="module"
module={module}
level={PermissionLevels.Enable}
>
<Tooltip title={title} placement="right">
<NavItem
to={`/organizations/${orgId}/${
name === 'toSub' ? subNavs[0].name : name
}`}
activeClassName="active"
{...(isActive && { isActive })}
>
{icon}
</NavItem>
</Tooltip>
</Access>
) : null;
})}
</Nav>
<Toolbar>
<DownloadListPopup
polling={downloadPolling}
setPolling={onSetPolling}
onLoadTasks={loadTasks}
onDownloadFile={item => {
if (item.id) {
downloadFile(item.id).then(() => {
dispatch(actions.setDownloadPolling(true));
});
}
}}
/>
{systemInfo?.tenantManagementMode ===
TenantManagementMode.Platform && (
<Popup
content={<OrganizationList />}
trigger={['click']}
placement="rightBottom"
onVisibleChange={organizationListVisibleChange}
>
<li>
<Tooltip title={t('nav.organization.title')} placement="right">
<Avatar
src={`${BASE_RESOURCE_URL}${currentOrganization?.avatar}`}
>
<BankFilled />
</Avatar>
</Tooltip>
</li>
</Popup>
)}
<Popup
content={
<Menu
prefixCls="ant-dropdown-menu"
selectable={false}
onClick={userMenuSelect}
>
<MenuListItem
key="language"
prefix={<GlobalOutlined className="icon" />}
title={<p>{t('nav.account.switchLanguage.title')}</p>}
sub
>
<MenuListItem key="zh">中文</MenuListItem>
<MenuListItem key="en">English</MenuListItem>
</MenuListItem>
<MenuListItem
key="theme"
prefix={<SkinOutlined className="icon" />}
title={<p>{t('nav.account.switchTheme.title')}</p>}
sub
>
<MenuListItem key="light" prefix={<ThemeBadge />}>
{t('nav.account.switchTheme.light')}
</MenuListItem>
<MenuListItem
key="dark"
prefix={<ThemeBadge background={BLACK} />}
>
{t('nav.account.switchTheme.dark')}
</MenuListItem>
</MenuListItem>
<Menu.Divider />
<MenuListItem
key="profile"
prefix={<ProfileOutlined className="icon" />}
>
<p>{t('nav.account.profile.title')}</p>
</MenuListItem>
<MenuListItem
key="password"
prefix={<FormOutlined className="icon" />}
>
<p>{t('nav.account.changePassword.title')}</p>
</MenuListItem>
<MenuListItem
key="logout"
prefix={<ExportOutlined className="icon" />}
>
<p>{t('nav.account.logout.title')}</p>
</MenuListItem>
</Menu>
}
trigger={['click']}
placement="rightBottom"
>
<li>
<Avatar src={`${BASE_RESOURCE_URL}${loggedInUser?.avatar}`}>
<UserOutlined />
</Avatar>
</li>
</Popup>
</Toolbar>
<Profile visible={profileVisible} onCancel={hideProfile} />
<ModifyPassword
visible={modifyPasswordVisible}
onCancel={hideModifyPassword}
/>
</MainNav>
{showSubNav && (
<SubNav>
<List
dataSource={subNavs}
renderItem={({ name, title, icon }) => (
<SubNavTitle
key={name}
to={`/organizations/${orgId}/${name}`}
activeClassName="active"
>
{cloneElement(icon, { className: 'prefix' })}
<h4>{title}</h4>
</SubNavTitle>
)}
/>
</SubNav>
)}
</>
);
}
Example #15
Source File: index.tsx From shippo with MIT License | 4 votes |
CreationLayout: React.FC = () => {
const [current, setCurrent] = useState('app1')
const handleClick: MenuClickEventHandler = (event) => {
console.log('click ', event)
setCurrent(event.key)
}
const onSearch = (value: string) => console.log(value)
const callback = (key: string) => {
console.log(key)
}
const data = [
{
icon: <FormOutlined />,
title: '投稿',
},
{
icon: <QuestionCircleOutlined />,
title: '帮助',
},
]
return (
<Layout>
<Header>
<div style={{ display: 'flex', backgroundColor: '#fff' }}>
<div style={{ width: '250px', fontSize: '25px', color: '#1890ff', textAlign: 'center' }}>
Shippo 创作中心
</div>
<div style={{ flex: '1 1 0%' }}>
<span style={{ fontSize: '16px', margin: '0 30px', color: '#757575' }}>
<CrownOutlined style={{ marginRight: '5px' }} />
主页
</span>
</div>
<div style={{ padding: '0 50px' }}>
<Dropdown
placement="bottomCenter"
overlay={
<Menu>
<Menu.Item>个人中心</Menu.Item>
<Menu.Item>投稿管理</Menu.Item>
<Menu.Divider />
<Menu.Item>退出登录</Menu.Item>
</Menu>
}
>
<Avatar size={40} icon={<UserOutlined />} />
</Dropdown>
</div>
</div>
</Header>
<Layout>
<Sider width="250px" theme="light" style={{ paddingTop: '20px' }}>
<Affix offsetTop={20} onChange={(affixed) => console.log(affixed)}>
<div style={{ overflow: 'auto', maxHeight: '100vh' }}>
<div style={{ padding: '10px 25px', textAlign: 'center' }}>
<Button type="primary" size="large" style={{ width: '120px' }}>
投稿
</Button>
</div>
<div style={{ padding: '0 25px' }}>
<StyledMenu
style={{ width: '200px', border: 0, backgroundColor: '#fff' }}
defaultSelectedKeys={['1']}
mode="inline"
>
<Menu.Item key="1" icon={<HomeOutlined />}>
首页
</Menu.Item>
<SubMenu key="sub1" icon={<FileTextOutlined />} title="内容管理">
<Menu.Item key="2">稿件管理</Menu.Item>
</SubMenu>
<Menu.Item key="5" icon={<TeamOutlined />}>
粉丝管理
</Menu.Item>
<SubMenu key="sub2" icon={<MessageOutlined />} title="互动管理">
<Menu.Item key="6">评论管理</Menu.Item>
</SubMenu>
<Menu.Item key="7" icon={<SettingOutlined />}>
创作设置
</Menu.Item>
</StyledMenu>
</div>
</div>
</Affix>
</Sider>
<Content>
<div style={{ padding: '30px 50px' }}>
<StyledTabs defaultActiveKey="1" style={{ backgroundColor: '#fff' }}>
<TabPane tab="文章管理" key="1">
<Tinymce></Tinymce>
</TabPane>
<TabPane tab="文章管理" key="2">
Content of Tab Pane 2
</TabPane>
<TabPane tab="文章管理" key="3">
Content of Tab Pane 3
</TabPane>
</StyledTabs>
</div>
</Content>
</Layout>
</Layout>
)
}
Example #16
Source File: index.tsx From foodie with MIT License | 4 votes |
Messages: React.FC<{ isAuth: boolean; }> = ({ isAuth }) => {
const id = useSelector((state: IRootReducer) => state.auth.id);
const [isMessagesOpen, setMessagesOpen] = useState(false);
const [isLoading, setLoading] = useState(false);
const [offset, setOffset] = useState(0);
const [error, setError] = useState<IError | null>(null);
const [messages, setMessages] = useState<IMessage[]>([]);
const [count, setCount] = useState(0);
const dispatch = useDispatch();
const composeModal = useModal();
const history = useHistory();
const isMessagesOpenRef = useRef(isMessagesOpen);
useEffect(() => {
isMessagesOpenRef.current = isMessagesOpen;
}, [isMessagesOpen]);
useEffect(() => {
if (isMessagesOpen) {
fetchMessages();
}
socket.on('newMessage', (newMessage: IMessage) => {
setMessages((prevMessages) => updateNewMessages(prevMessages, newMessage));
setCount((prevCount) => newMessage.isOwnMessage ? 0 : prevCount + 1);
});
document.addEventListener('click', handleClickOutside);
if (isAuth) {
getUnreadMessages()
.then((result) => {
setCount(result.count);
});
}
return () => {
socket.emit('userDisconnect', id);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const updateNewMessages = (prevMessages: IMessage[], newMessage: IMessage) => {
let messageOnList = false;
const updated = prevMessages
.map((msg) => {
const arr = [msg.from.username, msg.to.username];
if (arr.includes(newMessage.from.username) && arr.includes(newMessage.to.username)) {
messageOnList = true;
return newMessage;
}
return msg;
});
const sorted = updated.sort((a, b) => new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1);
return messageOnList ? sorted : [newMessage, ...sorted];
}
const handleClickOutside = (e: Event) => {
const toggle = (e.target as HTMLElement).closest('.messages-toggle');
const wrapper = (e.target as HTMLElement).closest('.messages-wrapper');
const seeMoreButton = (e.target as HTMLElement).closest('.see-more-button');
if (!toggle && isMessagesOpenRef.current && !wrapper && !seeMoreButton) {
setMessagesOpen(false);
}
}
const fetchMessages = async () => {
try {
setLoading(true);
setError(null);
const result = await getMessages({ offset });
setMessages([...messages, ...result]);
setOffset(offset + 1);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
};
const handleReadMessage = async (sender: IUser) => {
try {
dispatch(initiateChat(sender));
setMessagesOpen(false);
await readMessage(sender.id);
const updated = messages.map((msg) => {
if (msg.from.id === sender.id) {
return {
...msg,
seen: true
}
}
return msg;
});
setMessages(updated);
if (window.screen.width < 800) {
history.push(`/chat/${sender.username}`);
}
} catch (e) {
console.log(e);
}
}
const toggleMessages = () => {
setMessagesOpen(!isMessagesOpen);
setCount(0);
// Since setting state is asynchronous, we should flip the value of isMessagesOpen
if (!isMessagesOpen && messages.length === 0) {
fetchMessages();
}
}
const onClickCompose = () => {
composeModal.openModal();
setMessagesOpen(false);
}
const infiniteRef = useInfiniteScroll({
loading: isLoading,
hasNextPage: !error && messages.length >= 10,
onLoadMore: fetchMessages,
scrollContainer: 'parent',
});
return (
<div className="relative">
<div onClick={toggleMessages}>
<Badge count={count}>
<MessageOutlined className="messages-toggle text-xl focus:outline-none dark:text-white" />
</Badge>
</div>
{isMessagesOpen && (
<div className="messages-wrapper h-screen border border-transparent dark:border-gray-800 laptop:h-auto fixed top-14 laptop:top-10 pb-14 laptop:pb-0 right-0 w-full laptop:w-30rem bg-white dark:bg-indigo-1000 shadow-lg laptop:rounded-md laptop:absolute">
{/* ----- HEADER ----- */}
<div className="px-4 py-2 border-b-gray-200 flex justify-between items-center bg-indigo-700 laptop:rounded-t-md">
<h6 className="text-white">Messages</h6>
<span
className="text-sm flex p-2 text-white rounded-md hover:bg-indigo-500"
onClick={onClickCompose}
>
<FormOutlined className="mr-2" />
Compose
</span>
</div>
{/* --- LOADER FIRST FETCH */}
{(isLoading && !error && messages.length === 0) && (
<div className="flex items-center justify-center py-8">
<Loader />
</div>
)}
{/* --- ERROR MESSAGE ---- */}
{(messages.length === 0 && error) && (
<div className="flex justify-center py-6">
<p className="text-gray-400 italic">
{error.status_code === 404
? 'You have no messages.'
: (error?.error?.message || 'Something went wrong :(')
}
</p>
</div>
)}
{/* --- MSG LIST --- */}
{(messages.length !== 0) && (
<MessagesList
messages={messages}
handleReadMessage={handleReadMessage}
infiniteScrollRef={infiniteRef}
/>
)}
{/* ---- LOADER FETCHING MORE --- */}
{(isLoading && !error && messages.length !== 0) && (
<div className="flex items-center justify-center py-4">
<Loader />
</div>
)}
</div>
)}
{composeModal.isOpen && (
<ComposeMessageModal
isOpen={composeModal.isOpen}
openModal={composeModal.openModal}
closeModal={composeModal.closeModal}
userID={id}
/>
)}
</div>
);
}
Example #17
Source File: MixedArguments.tsx From yugong with MIT License | 4 votes |
Mixedarguments: React.FC<Props> = ({ typeArguments, onChange, className }) => {
const [jsonData, setJsonData] = useState<AppDataLayoutItemTypes>();
const [jsonMode, setJsonMode] = useState<'view' | 'code'>('view');
useEffect(() => {
const result = cloneDeep(typeArguments);
setJsonData(result.data || {});
}, [typeArguments]);
const jsoneditor = useRef<JSONEditor>();
const container = useRef<any>();
const onsubmit = useCallback(() => {
try {
var json = jsoneditor.current?.get();
if (json && onChange instanceof Function) {
const result = cloneDeep(typeArguments);
result.data = json;
jsoneditor.current?.setMode('view');
setJsonMode('view');
onChange(result);
message.success(`${typeArguments.name}已更新!`);
}
} catch (e) {
message.error('保存失败!JSON数据格式不正确');
return;
}
}, [onChange, typeArguments]);
useEffect(() => {
if (container.current && jsonData) {
jsoneditor.current = new JSONEditor(container.current, {
mode: jsonMode,
mainMenuBar: false,
});
jsoneditor.current.set(jsonData);
}
return () => {
if (jsoneditor.current) {
jsoneditor.current.destroy();
}
};
}, [jsonData, jsonMode]);
const onChangeJsonMode = useCallback((e) => {
try {
var json = jsoneditor.current?.get();
if (json) {
jsoneditor.current?.setMode('code');
setJsonMode('code');
}
} catch (error) {
console.error(error);
}
}, []);
return (
<div className={classNames(className)}>
<div className={s.toolbar} >
<div>
<CopyToClipboard
text={JSON.stringify(jsonData)}
onCopy={() => message.info('已复制到剪切板')}
>
<Button size="small" icon={<CopyOutlined alt="复制到剪切板" />}>
复制
</Button>
</CopyToClipboard>
{jsonMode === 'view' ? (
<Button
size="small"
type="primary"
onClick={onChangeJsonMode}
icon={<FormOutlined alt="编辑JSON" />}
>
编辑
</Button>
) : null}
{jsonMode === 'code' ? (
<Button
size="small"
type="primary"
onClick={onsubmit}
icon={<SaveOutlined alt="保存JSON" />}
>
保存
</Button>
) : null}
</div>
</div>
<div className={s.wrap} ref={container} />
</div>
);
}
Example #18
Source File: Icon.tsx From html2sketch with MIT License | 4 votes |
IconSymbol: FC = () => {
return (
<Row>
{/*<CaretUpOutlined*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/1.CaretUpOutlined'}*/}
{/*/>*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/2.MailOutlined'}*/}
{/*/>*/}
{/*<StepBackwardOutlined*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/2.StepBackwardOutlined'}*/}
{/*/>*/}
{/*<StepForwardOutlined*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/2.StepBackwardOutlined'}*/}
{/*/>*/}
<StepForwardOutlined />
<ShrinkOutlined />
<ArrowsAltOutlined />
<DownOutlined />
<UpOutlined />
<LeftOutlined />
<RightOutlined />
<CaretUpOutlined />
<CaretDownOutlined />
<CaretLeftOutlined />
<CaretRightOutlined />
<VerticalAlignTopOutlined />
<RollbackOutlined />
<FastBackwardOutlined />
<FastForwardOutlined />
<DoubleRightOutlined />
<DoubleLeftOutlined />
<VerticalLeftOutlined />
<VerticalRightOutlined />
<VerticalAlignMiddleOutlined />
<VerticalAlignBottomOutlined />
<ForwardOutlined />
<BackwardOutlined />
<EnterOutlined />
<RetweetOutlined />
<SwapOutlined />
<SwapLeftOutlined />
<SwapRightOutlined />
<ArrowUpOutlined />
<ArrowDownOutlined />
<ArrowLeftOutlined />
<ArrowRightOutlined />
<LoginOutlined />
<LogoutOutlined />
<MenuFoldOutlined />
<MenuUnfoldOutlined />
<BorderBottomOutlined />
<BorderHorizontalOutlined />
<BorderInnerOutlined />
<BorderOuterOutlined />
<BorderLeftOutlined />
<BorderRightOutlined />
<BorderTopOutlined />
<BorderVerticleOutlined />
<PicCenterOutlined />
<PicLeftOutlined />
<PicRightOutlined />
<RadiusBottomleftOutlined />
<RadiusBottomrightOutlined />
<RadiusUpleftOutlined />
<RadiusUprightOutlined />
<FullscreenOutlined />
<FullscreenExitOutlined />
<QuestionOutlined />
<PauseOutlined />
<MinusOutlined />
<PauseCircleOutlined />
<InfoOutlined />
<CloseOutlined />
<ExclamationOutlined />
<CheckOutlined />
<WarningOutlined />
<IssuesCloseOutlined />
<StopOutlined />
<EditOutlined />
<CopyOutlined />
<ScissorOutlined />
<DeleteOutlined />
<SnippetsOutlined />
<DiffOutlined />
<HighlightOutlined />
<AlignCenterOutlined />
<AlignLeftOutlined />
<AlignRightOutlined />
<BgColorsOutlined />
<BoldOutlined />
<ItalicOutlined />
<UnderlineOutlined />
<StrikethroughOutlined />
<RedoOutlined />
<UndoOutlined />
<ZoomInOutlined />
<ZoomOutOutlined />
<FontColorsOutlined />
<FontSizeOutlined />
<LineHeightOutlined />
<SortAscendingOutlined />
<SortDescendingOutlined />
<DragOutlined />
<OrderedListOutlined />
<UnorderedListOutlined />
<RadiusSettingOutlined />
<ColumnWidthOutlined />
<ColumnHeightOutlined />
<AreaChartOutlined />
<PieChartOutlined />
<BarChartOutlined />
<DotChartOutlined />
<LineChartOutlined />
<RadarChartOutlined />
<HeatMapOutlined />
<FallOutlined />
<RiseOutlined />
<StockOutlined />
<BoxPlotOutlined />
<FundOutlined />
<SlidersOutlined />
<AndroidOutlined />
<AppleOutlined />
<WindowsOutlined />
<IeOutlined />
<ChromeOutlined />
<GithubOutlined />
<AliwangwangOutlined />
<DingdingOutlined />
<WeiboSquareOutlined />
<WeiboCircleOutlined />
<TaobaoCircleOutlined />
<Html5Outlined />
<WeiboOutlined />
<TwitterOutlined />
<WechatOutlined />
<AlipayCircleOutlined />
<TaobaoOutlined />
<SkypeOutlined />
<FacebookOutlined />
<CodepenOutlined />
<CodeSandboxOutlined />
<AmazonOutlined />
<GoogleOutlined />
<AlipayOutlined />
<AntDesignOutlined />
<AntCloudOutlined />
<ZhihuOutlined />
<SlackOutlined />
<SlackSquareOutlined />
<BehanceSquareOutlined />
<DribbbleOutlined />
<DribbbleSquareOutlined />
<InstagramOutlined />
<YuqueOutlined />
<AlibabaOutlined />
<YahooOutlined />
<RedditOutlined />
<SketchOutlined />
<AccountBookOutlined />
<AlertOutlined />
<ApartmentOutlined />
<ApiOutlined />
<QqOutlined />
<MediumWorkmarkOutlined />
<GitlabOutlined />
<MediumOutlined />
<GooglePlusOutlined />
<AppstoreAddOutlined />
<AppstoreOutlined />
<AudioOutlined />
<AudioMutedOutlined />
<AuditOutlined />
<BankOutlined />
<BarcodeOutlined />
<BarsOutlined />
<BellOutlined />
<BlockOutlined />
<BookOutlined />
<BorderOutlined />
<BranchesOutlined />
<BuildOutlined />
<BulbOutlined />
<CalculatorOutlined />
<CalendarOutlined />
<CameraOutlined />
<CarOutlined />
<CarryOutOutlined />
<CiCircleOutlined />
<CiOutlined />
<CloudOutlined />
<ClearOutlined />
<ClusterOutlined />
<CodeOutlined />
<CoffeeOutlined />
<CompassOutlined />
<CompressOutlined />
<ContactsOutlined />
<ContainerOutlined />
<ControlOutlined />
<CopyrightCircleOutlined />
<CopyrightOutlined />
<CreditCardOutlined />
<CrownOutlined />
<CustomerServiceOutlined />
<DashboardOutlined />
<DatabaseOutlined />
<DeleteColumnOutlined />
<DeleteRowOutlined />
<DisconnectOutlined />
<DislikeOutlined />
<DollarCircleOutlined />
<DollarOutlined />
<DownloadOutlined />
<EllipsisOutlined />
<EnvironmentOutlined />
<EuroCircleOutlined />
<EuroOutlined />
<ExceptionOutlined />
<ExpandAltOutlined />
<ExpandOutlined />
<ExperimentOutlined />
<ExportOutlined />
<EyeOutlined />
<FieldBinaryOutlined />
<FieldNumberOutlined />
<FieldStringOutlined />
<DesktopOutlined />
<DingtalkOutlined />
<FileAddOutlined />
<FileDoneOutlined />
<FileExcelOutlined />
<FileExclamationOutlined />
<FileOutlined />
<FileImageOutlined />
<FileJpgOutlined />
<FileMarkdownOutlined />
<FilePdfOutlined />
<FilePptOutlined />
<FileProtectOutlined />
<FileSearchOutlined />
<FileSyncOutlined />
<FileTextOutlined />
<FileUnknownOutlined />
<FileWordOutlined />
<FilterOutlined />
<FireOutlined />
<FlagOutlined />
<FolderAddOutlined />
<FolderOutlined />
<FolderOpenOutlined />
<ForkOutlined />
<FormatPainterOutlined />
<FrownOutlined />
<FunctionOutlined />
<FunnelPlotOutlined />
<GatewayOutlined />
<GifOutlined />
<GiftOutlined />
<GlobalOutlined />
<GoldOutlined />
<GroupOutlined />
<HddOutlined />
<HeartOutlined />
<HistoryOutlined />
<HomeOutlined />
<HourglassOutlined />
<IdcardOutlined />
<ImportOutlined />
<InboxOutlined />
<InsertRowAboveOutlined />
<InsertRowBelowOutlined />
<InsertRowLeftOutlined />
<InsertRowRightOutlined />
<InsuranceOutlined />
<InteractionOutlined />
<KeyOutlined />
<LaptopOutlined />
<LayoutOutlined />
<LikeOutlined />
<LineOutlined />
<LinkOutlined />
<Loading3QuartersOutlined />
<LoadingOutlined />
<LockOutlined />
<MailOutlined />
<ManOutlined />
<MedicineBoxOutlined />
<MehOutlined />
<MenuOutlined />
<MergeCellsOutlined />
<MessageOutlined />
<MobileOutlined />
<MoneyCollectOutlined />
<MonitorOutlined />
<MoreOutlined />
<NodeCollapseOutlined />
<NodeExpandOutlined />
<NodeIndexOutlined />
<NotificationOutlined />
<NumberOutlined />
<PaperClipOutlined />
<PartitionOutlined />
<PayCircleOutlined />
<PercentageOutlined />
<PhoneOutlined />
<PictureOutlined />
<PoundCircleOutlined />
<PoundOutlined />
<PoweroffOutlined />
<PrinterOutlined />
<ProfileOutlined />
<ProjectOutlined />
<PropertySafetyOutlined />
<PullRequestOutlined />
<PushpinOutlined />
<QrcodeOutlined />
<ReadOutlined />
<ReconciliationOutlined />
<RedEnvelopeOutlined />
<ReloadOutlined />
<RestOutlined />
<RobotOutlined />
<RocketOutlined />
<SafetyCertificateOutlined />
<SafetyOutlined />
<ScanOutlined />
<ScheduleOutlined />
<SearchOutlined />
<SecurityScanOutlined />
<SelectOutlined />
<SendOutlined />
<SettingOutlined />
<ShakeOutlined />
<ShareAltOutlined />
<ShopOutlined />
<ShoppingCartOutlined />
<ShoppingOutlined />
<SisternodeOutlined />
<SkinOutlined />
<SmileOutlined />
<SolutionOutlined />
<SoundOutlined />
<SplitCellsOutlined />
<StarOutlined />
<SubnodeOutlined />
<SyncOutlined />
<TableOutlined />
<TabletOutlined />
<TagOutlined />
<TagsOutlined />
<TeamOutlined />
<ThunderboltOutlined />
<ToTopOutlined />
<ToolOutlined />
<TrademarkCircleOutlined />
<TrademarkOutlined />
<TransactionOutlined />
<TrophyOutlined />
<UngroupOutlined />
<UnlockOutlined />
<UploadOutlined />
<UsbOutlined />
<UserAddOutlined />
<UserDeleteOutlined />
<UserOutlined />
<UserSwitchOutlined />
<UsergroupAddOutlined />
<UsergroupDeleteOutlined />
<VideoCameraOutlined />
<WalletOutlined />
<WifiOutlined />
<BorderlessTableOutlined />
<WomanOutlined />
<BehanceOutlined />
<DropboxOutlined />
<DeploymentUnitOutlined />
<UpCircleOutlined />
<DownCircleOutlined />
<LeftCircleOutlined />
<RightCircleOutlined />
<UpSquareOutlined />
<DownSquareOutlined />
<LeftSquareOutlined />
<RightSquareOutlined />
<PlayCircleOutlined />
<QuestionCircleOutlined />
<PlusCircleOutlined />
<PlusSquareOutlined />
<MinusSquareOutlined />
<MinusCircleOutlined />
<InfoCircleOutlined />
<ExclamationCircleOutlined />
<CloseCircleOutlined />
<CloseSquareOutlined />
<CheckCircleOutlined />
<CheckSquareOutlined />
<ClockCircleOutlined />
<FormOutlined />
<DashOutlined />
<SmallDashOutlined />
<YoutubeOutlined />
<CodepenCircleOutlined />
<AliyunOutlined />
<PlusOutlined />
<LinkedinOutlined />
<AimOutlined />
<BugOutlined />
<CloudDownloadOutlined />
<CloudServerOutlined />
<CloudSyncOutlined />
<CloudUploadOutlined />
<CommentOutlined />
<ConsoleSqlOutlined />
<EyeInvisibleOutlined />
<FileGifOutlined />
<DeliveredProcedureOutlined />
<FieldTimeOutlined />
<FileZipOutlined />
<FolderViewOutlined />
<FundProjectionScreenOutlined />
<FundViewOutlined />
<MacCommandOutlined />
<PlaySquareOutlined />
<OneToOneOutlined />
<RotateLeftOutlined />
<RotateRightOutlined />
<SaveOutlined />
<SwitcherOutlined />
<TranslationOutlined />
<VerifiedOutlined />
<VideoCameraAddOutlined />
<WhatsAppOutlined />
{/*</Col>*/}
</Row>
);
}
Example #19
Source File: index.tsx From shippo with MIT License | 4 votes |
ReadLayout: React.FC = () => {
const [current, setCurrent] = useState('app1')
const handleClick: MenuClickEventHandler = (event) => {
console.log('click ', event)
setCurrent(event.key)
}
const onSearch = (value: string) => console.log(value)
const callback = (key: string) => {
console.log(key)
}
const data = [
{
icon: <FormOutlined />,
title: '投稿',
},
{
icon: <QuestionCircleOutlined />,
title: '帮助',
},
]
return (
<Layout>
<Header>
<div style={{ display: 'flex' }}>
<div>
<Menu
onClick={handleClick}
selectedKeys={[current]}
mode="horizontal"
style={{ borderBottom: '1px solid #fff' }}
>
<Menu.Item key="index" icon={<img width="40px" src={avatar} alt="" />}>
Shippo
</Menu.Item>
<Menu.Item key="app1">导航1</Menu.Item>
<Menu.Item key="app2">导航2</Menu.Item>
<Menu.Item key="app3">导航3</Menu.Item>
<Menu.Item key="app4">导航4</Menu.Item>
</Menu>
</div>
<div style={{ flex: '1 1 0%', backgroundColor: '#fff' }}>
<Search
placeholder=""
allowClear
onSearch={onSearch}
style={{ width: '100%', maxWidth: '500px', padding: '12px 10px 0 50px' }}
size="large"
/>
</div>
<div style={{ backgroundColor: '#fff', padding: '0 20px' }}>
<Space size={30}>
<Dropdown
placement="bottomCenter"
overlay={
<Menu>
<Menu.Item>个人中心</Menu.Item>
<Menu.Item>投稿管理</Menu.Item>
<Menu.Divider />
<Menu.Item>退出登录</Menu.Item>
</Menu>
}
>
<Avatar size={40} icon={<UserOutlined />} />
</Dropdown>
<Button type="primary">投稿</Button>
</Space>
</div>
</div>
</Header>
<Layout>
<Sider width="250px" theme="light" style={{ paddingTop: '20px' }}>
<Affix offsetTop={20} onChange={(affixed) => console.log(affixed)}>
<Menu
// onClick={handleClick}
style={{ width: '250px' }}
defaultSelectedKeys={['home']}
mode="inline"
>
<Menu.Item key="home" icon={<MailOutlined />}>
推荐
</Menu.Item>
<Menu.Item key="a" icon={<MailOutlined />}>
动画
</Menu.Item>
<Menu.Item key="c" icon={<MailOutlined />}>
漫画
</Menu.Item>
<Menu.Item key="g" icon={<MailOutlined />}>
游戏
</Menu.Item>
<Menu.Item key="n" icon={<MailOutlined />}>
轻小说
</Menu.Item>
</Menu>
</Affix>
</Sider>
<Content>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
<p style={{ height: '200px', padding: '30px' }}>内容</p>
</Content>
<Sider theme="light" width="300px" style={{ paddingTop: '20px' }}>
<Affix offsetTop={20} onChange={(affixed) => console.log(affixed)}>
<div style={{ overflow: 'auto', maxHeight: '100vh' }}>
<Search
placeholder="input search text"
allowClear
onSearch={onSearch}
style={{ width: '300px' }}
/>
<Card title="排行榜" bordered={false} style={{ width: '300px' }}>
<Tabs defaultActiveKey="1" onChange={callback}>
<TabPane tab="日榜" key="1">
日榜
</TabPane>
<TabPane tab="周榜" key="2">
周榜
</TabPane>
<TabPane tab="月榜" key="3">
月榜
</TabPane>
</Tabs>
</Card>
<Card title="更多" bordered={false} style={{ width: '300px' }}>
<List
itemLayout="horizontal"
dataSource={data}
split={false}
renderItem={(item) => (
<List.Item>
<List.Item.Meta
avatar={<Avatar shape="square" icon={item.icon} />}
title={<a href="https://ant.design">{item.title}</a>}
/>
</List.Item>
)}
/>
</Card>
</div>
</Affix>
</Sider>
</Layout>
</Layout>
)
}