@ant-design/icons#FullscreenExitOutlined TypeScript Examples
The following examples show how to use
@ant-design/icons#FullscreenExitOutlined.
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: index.tsx From covid_dashboard with MIT License | 6 votes |
render() {
return <div className='search-box'>
{this.state.items.length > 0 && <div className="search-result" style={{width: this.state.size === 'small' ? 300 : 450}}>
<div className="search-control">
<div className="control-btn" onClick={() => this.setState({size: this.state.size === 'small' ? 'large' : 'small'})}>{this.state.size === 'small' ? <FullscreenOutlined/> : <FullscreenExitOutlined/>}</div>
<div className="control-btn" onClick={() => this.setState({items: []})}><CloseCircleOutlined/></div>
</div>
<div className="search-items" style={{maxHeight: this.state.size === 'small' ? 350 : 500}}>
{this.state.items.map(item => {
return <div key={item._id} className="search-item" onClick={() => this.onClickEvent(item)}>
<div className="event-type" style={{background: getEventColor(item.type)}}>{_.capitalize(item.type)}</div>
<div className="event-time">{item.time}</div>
<div className="event-title">{item.title}</div>
</div>
})}
</div>
</div>}
<div className="search-input">
<Input.Search placeholder={this.props.intl.formatMessage({id: "search.placeholder"})} onChange={(e) => this.search(e.target.value)} onSearch={(text) => this.search(text)} loading={this.state.loading}/><span className='close' onClick={() => this.props.onClose && this.props.onClose()}><CloseCircleOutlined/></span>
</div>
</div>
}
Example #2
Source File: fitWindow.tsx From imove with MIT License | 6 votes |
FitWindow: React.FC<IProps> = makeBtnWidget({
tooltip: '适配窗口',
getIcon() {
return <FullscreenExitOutlined />;
},
handler(flowChart: Graph) {
flowChart.zoomToFit({ minScale: 0.5, maxScale: 1 });
},
})
Example #3
Source File: BuildingPanelCommon.tsx From condo with MIT License | 6 votes |
BuildingChooseSections: React.FC<IBuildingChooseSectionsProps> = (props) => {
const intl = useIntl()
const RequestFullscreenMessage = intl.formatMessage({ id: 'FullscreenRequest' })
const ExitFullscreenMessage = intl.formatMessage({ id: 'FullscreenExit' })
const {
toggleFullscreen,
isFullscreen,
mode = 'view',
children,
} = props
return (
<Row
css={FullscreenFooter}
gutter={FULLSCREEN_FOOTER_GUTTER}
>
<Col>
{mode === 'view' ? (
<Button
style={FULLSCREEN_BUTTON_STYLE}
type={'sberDefaultGradient'}
secondary
icon={isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
size={'large'}
onClick={toggleFullscreen}
>
{isFullscreen
? ExitFullscreenMessage
: RequestFullscreenMessage}
</Button>
) : children}
</Col>
</Row>
)
}
Example #4
Source File: Tile.tsx From ant-extensions with MIT License | 5 votes |
Tile: React.FC<ITileConfig> = React.memo((item) => {
const { isEditing, editWidget, renderWidget, findWidget } = useContext(Context);
const style = useMemo(
() => ({
color: item.color || "inherit"
}),
[item.color]
);
const [expanded, setExpanded] = useState(false);
const widget = useMemo(() => findWidget(item.widgetId), [findWidget, item.widgetId]);
return (
<Item item={item} expanded={!isEditing && expanded}>
<div className="ant-ext-pm__tileHead">
<span style={style}>{item.iconCls && <i className={item.iconCls} />}</span>
<label style={style}>{item.title}</label>
<div>
{item.info && (
<Tooltip
overlay={<pre dangerouslySetInnerHTML={{ __html: item.info }} />}
overlayClassName="ant-ext-pm__tileInfo"
>
<button>
<InfoCircleOutlined />
</button>
</Tooltip>
)}
{!isEditing && item.expandable && (
<button className="ant-ext-pm__tileExpander" onClick={() => setExpanded(!expanded)}>
{expanded ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
</button>
)}
{isEditing && (
<button onClick={() => editWidget(item.widgetId)}>
<EditOutlined />
</button>
)}
</div>
</div>
<div className="ant-ext-pm__tileBody">
{!isEditing && renderWidget(item.widgetId)}
{isEditing && widget && (
<div style={{ placeSelf: "center", textAlign: "center" }}>
{widget.icon}
<div>{widget.title}</div>
</div>
)}
</div>
</Item>
);
})
Example #5
Source File: Header.tsx From react_admin with MIT License | 4 votes |
Headers: React.FC<Iprops> = (props) => {
const { collapsed } = props;
const [fullScreen, setFullScreen] = useState(false); // 当前是否是全屏状态
// 进入全屏
const requestFullScreen = useCallback(() => {
const element: HTMLElement & Element = document.documentElement;
// 判断各种浏览器,找到正确的方法
const requestMethod =
element.requestFullscreen || // W3C
element.webkitRequestFullscreen || // Chrome等
element.mozRequestFullScreen || // FireFox
element.msRequestFullscreen; // IE11
if (requestMethod) {
requestMethod.call(element);
}
setFullScreen(true);
}, []);
// 退出登录
const onMenuClick = useCallback(
(e) => {
// 退出按钮被点击
if (e.key === "logout") {
props.onLogout();
}
},
[props]
);
// 退出全屏
const exitFullScreen = useCallback(() => {
// 判断各种浏览器,找到正确的方法
const element: Document & Element = document;
const exitMethod =
element.exitFullscreen || // W3C
element.mozCancelFullScreen || // firefox
element.webkitExitFullscreen || // Chrome等
element.msExitFullscreen; // IE11
if (exitMethod) {
exitMethod.call(document);
}
setFullScreen(false);
}, []);
const toggle = () => {
props.setColl(!collapsed);
};
return (
<Header className="site-layout-background header" style={{ padding: 0 }}>
<Tooltip title={props.collapsed ? "展开菜单" : "收起菜单"}>
{React.createElement(
collapsed ? MenuUnfoldOutlined : MenuFoldOutlined,
{
className: "trigger",
onClick: toggle,
}
)}
</Tooltip>
<div className="rightBox">
<Tooltip placement="bottom" title={fullScreen ? "退出全屏" : "全屏"}>
<div className="full all_center">
{fullScreen ? (
<FullscreenExitOutlined
className="icon"
onClick={exitFullScreen}
/>
) : (
<FullscreenOutlined
className="icon"
onClick={requestFullScreen}
/>
)}
</div>
</Tooltip>
<Dropdown
overlay={
<Menu className="menu" selectedKeys={[]} onClick={onMenuClick}>
<Menu.Item key="user">
<Link to="/home/user/admin">
<UserOutlined />
个人中心
</Link>
</Menu.Item>
<Menu.Item key="message">
<Link to="/home/user/level">
<MessageOutlined />
个人设置
</Link>
</Menu.Item>
<Menu.Divider />
<Menu.Item key="logout">
<LogoutOutlined />
退出登录
</Menu.Item>
</Menu>
}
placement="bottomRight"
>
<div className="userhead all_center">
<SmileOutlined />
<span className="username">admin</span>
</div>
</Dropdown>
</div>
</Header>
);
}
Example #6
Source File: DashboardHeader.tsx From posthog-foss with MIT License | 4 votes |
export function DashboardHeader(): JSX.Element {
const { dashboard, dashboardMode, lastDashboardModeSource } = useValues(dashboardLogic)
const { addNewDashboard, triggerDashboardUpdate, setDashboardMode, addGraph, saveNewTag, deleteTag } =
useActions(dashboardLogic)
const { dashboardTags } = useValues(dashboardsLogic)
const { nameSortedDashboards, dashboardsLoading, dashboardLoading } = useValues(dashboardsModel)
const { pinDashboard, unpinDashboard, deleteDashboard, duplicateDashboard } = useActions(dashboardsModel)
const { user } = useValues(userLogic)
const [newName, setNewName] = useState(dashboard?.name || null) // Used to update the input immediately, debouncing API calls
const nameInputRef = useRef<Input | null>(null)
const descriptionInputRef = useRef<HTMLInputElement | null>(null)
if (!dashboard) {
return <div />
}
const actionsDefault = (
<>
<Dropdown
trigger={['click']}
overlay={
<Menu>
{dashboard.created_by && (
<>
<Menu.Item disabled>
Created by {dashboard.created_by.first_name || dashboard.created_by.email || '-'} on{' '}
{dayjs(dashboard.created_at).format(
dayjs(dashboard.created_at).year() === dayjs().year()
? 'MMMM Do'
: 'MMMM Do YYYY'
)}
</Menu.Item>
<Menu.Divider />
</>
)}
<Menu.Item
icon={<EditOutlined />}
onClick={() => setDashboardMode(DashboardMode.Edit, DashboardEventSource.MoreDropdown)}
>
Edit mode (E)
</Menu.Item>
<Menu.Item
icon={<FullscreenOutlined />}
onClick={() =>
setDashboardMode(DashboardMode.Fullscreen, DashboardEventSource.MoreDropdown)
}
>
Full screen mode (F)
</Menu.Item>
{dashboard.pinned ? (
<Menu.Item
icon={<PushpinFilled />}
onClick={() => unpinDashboard(dashboard.id, DashboardEventSource.MoreDropdown)}
>
Unpin dashboard
</Menu.Item>
) : (
<Menu.Item
icon={<PushpinOutlined />}
onClick={() => pinDashboard(dashboard.id, DashboardEventSource.MoreDropdown)}
>
Pin dashboard
</Menu.Item>
)}
<Menu.Divider />
<Menu.Item
icon={<CopyOutlined />}
onClick={() => duplicateDashboard({ id: dashboard.id, name: dashboard.name, show: true })}
>
Duplicate dashboard
</Menu.Item>
<Menu.Item
icon={<DeleteOutlined />}
onClick={() => deleteDashboard({ id: dashboard.id, redirect: true })}
danger
>
Delete dashboard
</Menu.Item>
</Menu>
}
placement="bottomRight"
>
<Button type="link" className="btn-lg-2x" data-attr="dashboard-more" icon={<EllipsisOutlined />} />
</Dropdown>
<Button
type="link"
data-attr="dashboard-edit-mode"
icon={<EditOutlined />}
onClick={() => setDashboardMode(DashboardMode.Edit, DashboardEventSource.DashboardHeader)}
/>
<HotkeyButton
onClick={() => addGraph()}
data-attr="dashboard-add-graph-header"
icon={<PlusOutlined />}
hotkey="n"
className="hide-lte-md"
>
New insight
</HotkeyButton>
<HotkeyButton
type="primary"
onClick={() => setDashboardMode(DashboardMode.Sharing, DashboardEventSource.DashboardHeader)}
data-attr="dashboard-share-button"
icon={<ShareAltOutlined />}
hotkey="k"
>
Send or share
</HotkeyButton>
</>
)
const actionsPresentationMode = (
<Button
onClick={() => setDashboardMode(null, DashboardEventSource.DashboardHeader)}
data-attr="dashboard-exit-presentation-mode"
icon={<FullscreenExitOutlined />}
>
Exit full screen mode
</Button>
)
const actionsEditMode = (
<Button
data-attr="dashboard-edit-mode-save"
type="primary"
onClick={() => setDashboardMode(null, DashboardEventSource.DashboardHeader)}
tabIndex={10}
>
Finish editing
</Button>
)
useEffect(() => {
if (dashboardMode === DashboardMode.Edit) {
if (lastDashboardModeSource === DashboardEventSource.AddDescription) {
setTimeout(() => descriptionInputRef.current?.focus(), 10)
} else if (!isMobile()) {
setTimeout(() => nameInputRef.current?.focus(), 10)
}
}
}, [dashboardMode])
return (
<>
<div className={`dashboard-header${dashboardMode === DashboardMode.Fullscreen ? ' full-screen' : ''}`}>
{dashboardMode === DashboardMode.Fullscreen && (
<FullScreen onExit={() => setDashboardMode(null, DashboardEventSource.Browser)} />
)}
<ShareModal
onCancel={() => setDashboardMode(null, DashboardEventSource.Browser)}
visible={dashboardMode === DashboardMode.Sharing}
/>
{dashboardsLoading ? (
<Loading />
) : (
<>
{dashboardMode === DashboardMode.Edit ? (
<Input
placeholder="Dashboard name (e.g. Weekly KPIs)"
value={newName || ''}
size="large"
style={{ maxWidth: 400 }}
onChange={(e) => {
setNewName(e.target.value) // To update the input immediately
triggerDashboardUpdate({ name: e.target.value }) // This is breakpointed (i.e. debounced) to avoid multiple API calls
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
setDashboardMode(null, DashboardEventSource.InputEnter)
}
}}
ref={nameInputRef}
tabIndex={0}
/>
) : (
<div className="dashboard-select">
<Select
value={(dashboard?.id || undefined) as number | 'new' | undefined}
onChange={(id) => {
if (id === 'new') {
addNewDashboard()
} else {
router.actions.push(urls.dashboard(id))
eventUsageLogic.actions.reportDashboardDropdownNavigation()
}
}}
bordered={false}
dropdownMatchSelectWidth={false}
>
{nameSortedDashboards.map((dash: DashboardType) => (
<Select.Option key={dash.id} value={dash.id}>
{dash.name || <span style={{ color: 'var(--muted)' }}>Untitled</span>}
{dash.is_shared && (
<Tooltip title="This dashboard is publicly shared">
<ShareAltOutlined style={{ marginLeft: 4, float: 'right' }} />
</Tooltip>
)}
</Select.Option>
))}
<Select.Option value="new">+ New Dashboard</Select.Option>
</Select>
</div>
)}
<div className="dashboard-meta">
{dashboardMode === DashboardMode.Edit
? actionsEditMode
: dashboardMode === DashboardMode.Fullscreen
? actionsPresentationMode
: actionsDefault}
</div>
</>
)}
</div>
{user?.organization?.available_features?.includes(AvailableFeature.DASHBOARD_COLLABORATION) && (
<>
<div className="mb" data-attr="dashboard-tags">
<ObjectTags
tags={dashboard.tags}
onTagSave={saveNewTag}
onTagDelete={deleteTag}
saving={dashboardLoading}
tagsAvailable={dashboardTags.filter((tag) => !dashboard.tags.includes(tag))}
/>
</div>
<Description
item={dashboard}
setItemMode={setDashboardMode}
itemMode={dashboardMode}
triggerItemUpdate={triggerDashboardUpdate}
descriptionInputRef={descriptionInputRef}
/>
</>
)}
</>
)
}
Example #7
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 #8
Source File: BuilderToolbar.spec.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
describe("BuilderToolbar", () => {
beforeEach(() => {
jest.clearAllMocks();
});
it("should work", async () => {
mockUseBuilderUIContext.mockReturnValue({
onCurrentRouteClick: mockCurrentRouteClick,
onBuildAndPush: mockBuildAndPush,
onPreview: mockPreview,
dataType: BuilderDataType.ROUTE_OF_BRICKS,
});
mockUseBuilderNode.mockReturnValue({
id: "R-01",
type: "bricks",
path: "/",
});
const wrapper = shallow(<BuilderToolbar />);
expect(wrapper.find(".tabLink").length).toBe(6);
wrapper.find(".tabLink[data-testid='view-route']").simulate("click");
expect(mockCurrentRouteClick).toBeCalledWith({
id: "R-01",
type: "bricks",
path: "/",
});
wrapper.find(".tabLink[data-testid='build-and-push']").simulate("click");
expect(mockBuildAndPush).toBeCalled();
wrapper.find(".tabLink[data-testid='preview']").simulate("click");
expect(mockPreview).toBeCalled();
});
it("should work with custom template", async () => {
mockUseBuilderUIContext.mockReturnValue({
onCurrentTemplateClick: mockCurrentTemplateClick,
onCurrentSnippetClick: mockCurrentSnippetClick,
onCurrentRouteClick: mockCurrentRouteClick,
onBuildAndPush: mockBuildAndPush,
onPreview: mockPreview,
dataType: BuilderDataType.CUSTOM_TEMPLATE,
});
mockUseBuilderNode.mockReturnValue({
id: "T-01",
type: "custom-template",
templateId: "tpl-test",
});
const wrapper = shallow(<BuilderToolbar />);
expect(wrapper.find(".tabLink").length).toBe(6);
expect(
wrapper.find(".tabLink").filter("[data-testid='view-template']").length
).toBe(1);
wrapper
.find(".tabLink")
.filter("[data-testid='view-template']")
.simulate("click");
expect(mockCurrentTemplateClick).toBeCalled();
});
it("should work with snippet", async () => {
mockUseBuilderUIContext.mockReturnValue({
onCurrentTemplateClick: mockCurrentTemplateClick,
onCurrentSnippetClick: mockCurrentSnippetClick,
onCurrentRouteClick: mockCurrentRouteClick,
onBuildAndPush: mockBuildAndPush,
onPreview: mockPreview,
dataType: BuilderDataType.SNIPPET,
});
mockUseBuilderNode.mockReturnValue({
id: "S-01",
type: "snippet",
snippetId: "snippet-test",
});
const wrapper = shallow(<BuilderToolbar />);
expect(wrapper.find(".tabLink").length).toBe(6);
expect(
wrapper.find(".tabLink").filter("[data-testid='view-snippet']").length
).toBe(1);
wrapper
.find(".tabLink")
.filter("[data-testid='view-snippet']")
.simulate("click");
expect(mockCurrentSnippetClick).toBeCalled();
});
it("should enter fullscreen", () => {
let fullscreen = false;
const setFullscreen = jest.fn((update) => {
fullscreen = update(fullscreen);
});
mockUseBuilderUIContext.mockImplementation(() => ({
fullscreen,
setFullscreen,
}));
const wrapper = shallow(<BuilderToolbar />);
expect(wrapper.find(FullscreenOutlined).length).toBe(1);
expect(wrapper.find(FullscreenExitOutlined).length).toBe(0);
wrapper.find(".tabLink[data-testid='toggle-fullscreen']").invoke("onClick")(
null
);
expect(setFullscreen).toBeCalled();
expect(fullscreen).toBe(true);
});
it("should invoke onWorkbenchClose", () => {
const onWorkbenchClose = jest.fn();
mockUseBuilderUIContext.mockImplementation(() => ({
onWorkbenchClose,
}));
const wrapper = shallow(<BuilderToolbar />);
wrapper.find(".tabLink[data-testid='workbench-close']").invoke("onClick")(
null
);
expect(onWorkbenchClose).toBeCalled();
});
it("should show layer viewer ", () => {
(getRuntime as jest.Mock).mockReturnValueOnce({
getFeatureFlags: jest
.fn()
.mockReturnValue({ "next-builder-layer-view": true }),
});
const wrapper = shallow(<BuilderToolbar />);
expect(wrapper.find(LibraryDropdown).length).toEqual(3);
wrapper.find(LibraryDropdown).at(0).invoke("onVisbleChange")(true);
wrapper.find(LibraryDropdown).at(1).invoke("onVisbleChange")(true);
wrapper.find(LibraryDropdown).at(2).invoke("onVisbleChange")(true);
const tooltipWrapper = wrapper.find(LibraryDropdown).at(0).shallow();
expect(tooltipWrapper.find(Tooltip).at(0).prop("overlayStyle")).toEqual({
display: "none",
});
});
it("should show the hidden wrapper switch", () => {
mockUseBuilderUIContext.mockReturnValue({
onCurrentRouteClick: mockCurrentRouteClick,
onBuildAndPush: mockBuildAndPush,
onPreview: mockPreview,
dataType: BuilderDataType.ROUTE_OF_BRICKS,
hiddenWrapper: true,
setHiddenWrapper: mockSetHiddenWrapper,
});
mockUseBuilderNode.mockReturnValue({
id: "R-01",
type: "bricks",
path: "/",
});
mockUseBuilderData.mockReturnValue({
wrapperNode: {
$$uid: 1,
},
} as any);
const wrapper = shallow(<BuilderToolbar />);
expect(wrapper.find(Switch).length).toBe(1);
wrapper.find(Switch).prop("onChange")(true, {} as MouseEvent);
expect(mockSetHiddenWrapper).toBeCalled();
});
});
Example #9
Source File: BuilderToolbar.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
export function BuilderToolbar(): React.ReactElement {
const { t } = useTranslation(NS_NEXT_BUILDER);
const enableLayerView = React.useMemo(
() => getRuntime().getFeatureFlags()["next-builder-layer-view"],
[]
);
const [libsDropdownVisible, setLibsDropdownVisible] = useState<{
[key in typeof LayerType[keyof typeof LayerType]]: boolean;
}>({
[LayerType.LAYOUT]: false,
[LayerType.WIDGET]: false,
[LayerType.BRICK]: false,
});
const { wrapperNode } = useBuilderData();
const {
onCurrentRouteClick,
onCurrentTemplateClick,
onCurrentSnippetClick,
onBuildAndPush,
onPreview,
dataType,
fullscreen,
setFullscreen,
onWorkbenchClose,
hiddenWrapper,
setHiddenWrapper,
} = useBuilderUIContext();
const rootNode = useBuilderNode({ isRoot: true });
const handleRouteClick = (): void => {
onCurrentRouteClick?.(rootNode as BuilderRouteNode);
};
const handleTemplateClick = (): void => {
onCurrentTemplateClick?.(rootNode as BuilderCustomTemplateNode);
};
const handleSnippetClick = (): void => {
onCurrentSnippetClick?.(rootNode as BuilderSnippetNode);
};
const handlePreview = (): void => {
onPreview?.();
};
const handleBuildAndPush = (): void => {
onBuildAndPush?.();
};
const handleToggleFullscreen = React.useCallback(() => {
setFullscreen((prev) => !prev);
}, [setFullscreen]);
const handleClose = (): void => {
onWorkbenchClose?.();
};
const divider = useMemo(
() => <Divider type="vertical" style={{ height: 25 }} />,
[]
);
return (
<div className={styles.toolbarContainer}>
<div className={styles.toolbarLeft}>
{dataType === BuilderDataType.SNIPPET ? (
<Tooltip title={t(K.VIEW_SNIPPET)} placement="bottomLeft">
<a
className={shareStyles.tabLink}
role="button"
onClick={handleSnippetClick}
data-testid="view-snippet"
>
<BlockOutlined />
</a>
</Tooltip>
) : dataType === BuilderDataType.CUSTOM_TEMPLATE ? (
<Tooltip title={t(K.VIEW_TEMPLATE)} placement="bottomLeft">
<a
className={shareStyles.tabLink}
role="button"
onClick={handleTemplateClick}
data-testid="view-template"
>
<BlockOutlined />
</a>
</Tooltip>
) : (
<Tooltip title={t(K.VIEW_ROUTE)} placement="bottomLeft">
<a
className={shareStyles.tabLink}
role="button"
onClick={handleRouteClick}
data-testid="view-route"
>
<BranchesOutlined />
</a>
</Tooltip>
)}
<RootNodeSelect />
</div>
<div className={styles.toolbarRight}>
{wrapperNode ? (
<Switch
checkedChildren="显示布局"
unCheckedChildren="隐藏布局"
checked={hiddenWrapper}
onChange={setHiddenWrapper}
size="small"
style={{
marginRight: 10,
top: -1,
}}
/>
) : null}
{enableLayerView && (
<>
<LibraryDropdown
menuItems={layoutMenus}
type={LayerType.LAYOUT}
onVisbleChange={(visible) =>
setLibsDropdownVisible({
...libsDropdownVisible,
[LayerType.LAYOUT]: visible,
})
}
>
<Tooltip
title={t(K.LAYOUT_LIBRARY)}
placement="bottomRight"
overlayStyle={{
// Hide tooltip when dropdown is open.
display: libsDropdownVisible[LayerType.LAYOUT]
? "none"
: undefined,
}}
>
<Button
type="link"
size="small"
className={shareStyles.tabLink}
style={{ marginRight: "10px" }}
>
<LayoutOutlined />
</Button>
</Tooltip>
</LibraryDropdown>
<LibraryDropdown
menuItems={widgetMenus}
type={LayerType.WIDGET}
onVisbleChange={(visible) =>
setLibsDropdownVisible({
...libsDropdownVisible,
[LayerType.WIDGET]: visible,
})
}
>
<Tooltip
title={t(K.WIDGET_LIBRARY)}
placement="bottomRight"
overlayStyle={{
display: libsDropdownVisible[LayerType.WIDGET]
? "none"
: undefined,
}}
>
<Button
type="link"
size="small"
className={shareStyles.tabLink}
style={{ marginRight: "10px" }}
>
<GoldOutlined />
</Button>
</Tooltip>
</LibraryDropdown>
</>
)}
<LibraryDropdown
menuItems={brickMenus}
type={LayerType.BRICK}
onVisbleChange={(visible) =>
setLibsDropdownVisible({
...libsDropdownVisible,
[LayerType.BRICK]: visible,
})
}
>
<Tooltip
title={t(K.BRICK_LIBRARY)}
placement="bottomRight"
overlayStyle={{
display: libsDropdownVisible[LayerType.BRICK]
? "none"
: undefined,
}}
>
<Button
type="link"
size="small"
style={{ marginRight: "10px" }}
className={shareStyles.tabLink}
>
<PlusOutlined />
</Button>
</Tooltip>
</LibraryDropdown>
{divider}
<Tooltip title={t(K.BUILD_AND_PUSH_TOOLTIP)} placement="bottomRight">
<a
className={shareStyles.tabLink}
role="button"
onClick={handleBuildAndPush}
data-testid="build-and-push"
>
<ApiOutlined />
</a>
</Tooltip>
<Tooltip title={t(K.PREVIEW)} placement="bottomRight">
<a
className={shareStyles.tabLink}
role="button"
onClick={handlePreview}
data-testid="preview"
>
<CaretRightOutlined />
</a>
</Tooltip>
{divider}
<SettingDropdown />
{!fullscreen && (
<Tooltip
title={t(fullscreen ? K.EXIT_FULLSCREEN : K.ENTER_FULLSCREEN)}
placement="bottomRight"
>
<a
className={shareStyles.tabLink}
role="button"
onClick={handleToggleFullscreen}
data-testid="toggle-fullscreen"
>
{fullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
</a>
</Tooltip>
)}
<Tooltip title={t(K.CLOSE)} placement="bottomRight">
<a
className={shareStyles.tabLink}
role="button"
onClick={handleClose}
data-testid="workbench-close"
>
<CloseOutlined />
</a>
</Tooltip>
</div>
</div>
);
}
Example #10
Source File: useExtraBtn.tsx From amiya with MIT License | 4 votes |
export default function useExtraBtn(
tableRef: any,
searchRef: any,
tableFields: Array<AyTableField>,
setTableFields: Dispatch<React.SetStateAction<AyTableField[]>>,
props: AySearchTableProps
) {
// 合并配置
const config = Object.assign({}, defaultConfig, props)
const {
extraVisible,
extraRefreshVisible,
extraSizeVisible,
extraSizeDefaultValue,
extraSettingVisible,
extraFullscreenVisible
} = config
/** 表格尺寸 */
const [size, setSize] = useState<SizeType>(extraSizeDefaultValue)
/** 表格全屏 */
const [isEnter, setIsEnter] = useState<boolean>(false)
const fieldsEdit = useFieldsEdit(tableFields, setTableFields)
const handleRefresh = () => {
tableRef.current.refresh()
}
const handleSizeChange = (e: any) => {
setSize(e.key)
}
useEffect(() => {
// body 的 style 防止滚动
if (isEnter) {
document.body.style.overflow = 'hidden'
} else {
document.body.style.overflow = ''
}
searchRef.current && searchRef.current.resize()
}, [isEnter])
const extraBtns = extraVisible ? (
<div className="ay-search-table-extra-btns" key="ay-search-table-extra-btns">
<Space size="middle">
{extraRefreshVisible ? (
<Tooltip title={locale.extra.refresh}>
<ReloadOutlined onClick={handleRefresh} />
</Tooltip>
) : null}
{extraSizeVisible ? (
<Tooltip title={locale.extra.density}>
<Dropdown
overlay={
<Menu style={{ width: 100 }} selectedKeys={[size + '']} onClick={handleSizeChange}>
<Menu.Item key="large">{locale.extra.densityLarger}</Menu.Item>
<Menu.Item key="middle">{locale.extra.densityMiddle}</Menu.Item>
<Menu.Item key="small">{locale.extra.densitySmall}</Menu.Item>
</Menu>
}
>
<ColumnHeightOutlined />
</Dropdown>
</Tooltip>
) : null}
{extraSettingVisible ? fieldsEdit : null}
{extraFullscreenVisible ? (
isEnter ? (
<Tooltip title={locale.extra.exitFullScreen} key={locale.extra.exitFullScreen}>
<FullscreenExitOutlined className="ay-search-table-fullscrenn-enter" onClick={() => setIsEnter(false)} />
</Tooltip>
) : (
<Tooltip title={locale.extra.fullScreen} key={locale.extra.fullScreen}>
<FullscreenOutlined className="ay-search-table-fullscrenn-out" onClick={() => setIsEnter(true)} />
</Tooltip>
)
) : null}
</Space>
</div>
) : null
return {
extraBtns,
isEnter,
setIsEnter,
size
}
}
Example #11
Source File: YakExecutor.tsx From yakit with GNU Affero General Public License v3.0 | 4 votes |
YakExecutor: React.FC<YakExecutorProp> = (props) => {
const [codePath, setCodePath] = useState<string>("")
const [loading, setLoading] = useState<boolean>(false)
const [fileList, setFileList] = useState<tabCodeProps[]>([])
const [tabList, setTabList] = useState<tabCodeProps[]>([])
const [activeTab, setActiveTab] = useState<string>("")
const [unTitleCount, setUnTitleCount] = useState(1)
const [hintShow, setHintShow] = useState<boolean>(false)
const [hintFile, setHintFile] = useState<string>("")
const [hintIndex, setHintIndex] = useState<number>(0)
const [renameHint, setRenameHint] = useState<boolean>(false)
const [renameIndex, setRenameIndex] = useState<number>(-1)
const [renameFlag, setRenameFlag] = useState<boolean>(false)
const [renameCache, setRenameCache] = useState<string>("")
const [fullScreen, setFullScreen] = useState<boolean>(false)
const [errors, setErrors] = useState<string[]>([])
const [executing, setExecuting] = useState(false)
const [outputEncoding, setOutputEncoding] = useState<"utf8" | "latin1">("utf8")
const xtermAsideRef = useRef(null)
const xtermRef = useRef(null)
const timer = useRef<any>(null)
const [extraParams, setExtraParams] = useState("")
// trigger for updating
const [triggerForUpdatingHistory, setTriggerForUpdatingHistory] = useState<any>(0)
const addFileTab = useMemoizedFn((res: any) => {
const {name, code} = res
const tab: tabCodeProps = {
tab: `${name}.yak`,
code: code,
suffix: "yak",
isFile: false
}
setActiveTab(`${tabList.length}`)
setTabList(tabList.concat([tab]))
setUnTitleCount(unTitleCount + 1)
})
useEffect(() => {
ipcRenderer.on("fetch-send-to-yak-running", (e, res: any) => addFileTab(res))
return () => ipcRenderer.removeAllListeners("fetch-send-to-yak-running")
}, [])
// 自动保存
const autoSave = useMemoizedFn(() => {
for (let tabInfo of tabList) {
if (tabInfo.isFile) {
ipcRenderer.invoke("write-file", {
route: tabInfo.route,
data: tabInfo.code
})
}
}
})
// 保存近期文件内的15个
const saveFiliList = useMemoizedFn(() => {
let files = cloneDeep(fileList).reverse()
files.splice(14)
files = files.reverse()
ipcRenderer.invoke("set-value", RecentFileList, files)
})
// 获取和保存近期打开文件信息,同时展示打开默认内容
useEffect(() => {
let time: any = null
let timer: any = null
setLoading(true)
ipcRenderer
.invoke("get-value", RecentFileList)
.then((value: any) => {
if ((value || []).length !== 0) {
setFileList(value)
} else {
const tab: tabCodeProps = {
tab: `Untitle-${unTitleCount}.yak`,
code: "# input your yak code\nprintln(`Hello Yak World!`)",
suffix: "yak",
isFile: false
}
setActiveTab(`${tabList.length}`)
setTabList([tab])
setUnTitleCount(unTitleCount + 1)
}
})
.catch(() => {})
.finally(() => {
setTimeout(() => setLoading(false), 300)
time = setInterval(() => {
autoSave()
}, 2000)
timer = setInterval(() => {
saveFiliList()
}, 5000)
})
return () => {
saveFiliList()
if (time) clearInterval(time)
if (timer) clearInterval(timer)
}
}, [])
// 全局监听重命名事件是否被打断
useEffect(() => {
document.onmousedown = (e) => {
// @ts-ignore
if (e.path[0].id !== "rename-input" && renameFlag) {
renameCode(renameIndex)
setRenameFlag(false)
}
}
}, [renameFlag])
// 打开文件
const addFile = useMemoizedFn((file: any) => {
const isExists = fileList.filter((item) => item.tab === file.name && item.route === file.path).length === 1
if (isExists) {
for (let index in tabList) {
const item = tabList[index]
if (item.tab === file.name && item.route === file.path) {
setActiveTab(`${index}`)
return false
}
}
}
ipcRenderer
.invoke("fetch-file-content", file.path)
.then((res) => {
const tab: tabCodeProps = {
tab: file.name,
code: res,
suffix: file.name.split(".").pop() === "yak" ? "yak" : "http",
isFile: true,
route: file.path,
extraParams: file.extraParams
}
setActiveTab(`${tabList.length}`)
if (!isExists) setFileList(fileList.concat([tab]))
setTabList(tabList.concat([tab]))
})
.catch(() => {
failed("无法获取该文件内容,请检查后后重试!")
const files = cloneDeep(fileList)
for (let i in files) if (files[i].route === file.path) files.splice(i, 1)
setFileList(files)
})
return false
})
// 新建文件
const newFile = useMemoizedFn(() => {
const tab: tabCodeProps = {
tab: `Untitle-${unTitleCount}.yak`,
code: "# input your yak code\nprintln(`Hello Yak World!`)",
suffix: "yak",
isFile: false
}
setActiveTab(`${tabList.length}`)
setTabList(tabList.concat([tab]))
setUnTitleCount(unTitleCount + 1)
})
//修改文件
const modifyCode = useMemoizedFn((value: string, index: number) => {
const tabs = cloneDeep(tabList)
tabs[index].code = value
setTabList(tabs)
})
// 保存文件
const saveCode = useMemoizedFn((info: tabCodeProps, index: number) => {
if (info.isFile) {
ipcRenderer.invoke("write-file", {
route: info.route,
data: info.code
})
} else {
ipcRenderer.invoke("show-save-dialog", `${codePath}${codePath ? '/' : ''}${info.tab}`).then((res) => {
if (res.canceled) return
const path = res.filePath
const name = res.name
ipcRenderer
.invoke("write-file", {
route: res.filePath,
data: info.code
})
.then(() => {
const suffix = name.split(".").pop()
var tabs = cloneDeep(tabList)
var active = null
tabs = tabs.filter((item) => item.route !== path)
tabs = tabs.map((item, index) => {
if (!item.route && item.tab === info.tab) {
active = index
item.tab = name
item.isFile = true
item.suffix = suffix === "yak" ? suffix : "http"
item.route = path
return item
}
return item
})
if (active !== null) setActiveTab(`${active}`)
setTabList(tabs)
const file: tabCodeProps = {
tab: name,
code: info.code,
isFile: true,
suffix: suffix === "yak" ? suffix : "http",
route: res.filePath,
extraParams: info.extraParams
}
for (let item of fileList) {
if (item.route === file.route) {
return
}
}
setFileList(fileList.concat([file]))
})
})
}
})
//关闭文件
const closeCode = useMemoizedFn((index, isFileList: boolean) => {
const tabInfo = isFileList ? fileList[+index] : tabList[+index]
if (isFileList) {
for (let i in tabList) {
if (tabList[i].tab === tabInfo.tab && tabList[i].route === tabInfo.route) {
const tabs = cloneDeep(tabList)
tabs.splice(i, 1)
setTabList(tabs)
setActiveTab(tabs.length >= 1 ? `0` : "")
}
}
const files = cloneDeep(fileList)
files.splice(+index, 1)
setFileList(files)
} else {
setActiveTab(index)
if (!tabInfo.isFile) {
setHintFile(tabInfo.tab)
setHintIndex(index)
setHintShow(true)
} else {
const tabs = cloneDeep(tabList)
tabs.splice(+index, 1)
setTabList(tabs)
setActiveTab(tabs.length >= 1 ? `0` : "")
}
}
})
// 关闭虚拟文件不保存
const ownCloseCode = useMemoizedFn(() => {
const tabs = cloneDeep(tabList)
tabs.splice(hintIndex, 1)
setTabList(tabs)
setHintShow(false)
setActiveTab(tabs.length >= 1 ? `0` : "")
})
// 删除文件
const delCode = useMemoizedFn((index) => {
const fileInfo = fileList[index]
ipcRenderer
.invoke("delelte-code-file", fileInfo.route)
.then(() => {
for (let i in tabList) {
if (tabList[i].tab === fileInfo.tab && tabList[i].route === fileInfo.route) {
const tabs = cloneDeep(tabList)
tabs.splice(i, 1)
setTabList(tabs)
setActiveTab(tabs.length >= 1 ? `0` : "")
}
}
const arr = cloneDeep(fileList)
arr.splice(index === undefined ? hintIndex : index, 1)
setFileList(arr)
})
.catch(() => {
failed("文件删除失败!")
})
})
//重命名操作
const renameCode = useMemoizedFn((index: number) => {
const tabInfo = fileList[index]
if (renameCache === tabInfo.tab) return
if (!renameCache) return
if (!tabInfo.route) return
const flagStr = tabInfo.route?.indexOf("/") > -1 ? "/" : "\\"
const routes = tabInfo.route?.split(flagStr)
routes?.pop()
ipcRenderer
.invoke("is-exists-file", routes?.concat([renameCache]).join(flagStr))
.then(() => {
const newRoute = routes?.concat([renameCache]).join(flagStr)
if (!tabInfo.route || !newRoute) return
renameFile(index, renameCache, tabInfo.route, newRoute)
})
.catch(() => {
setRenameHint(true)
})
})
// 重命名文件
const renameFile = useMemoizedFn(
(index: number, rename: string, oldRoute: string, newRoute: string, callback?: () => void) => {
ipcRenderer.invoke("rename-file", {old: oldRoute, new: newRoute}).then(() => {
const suffix = rename.split(".").pop()
var files = cloneDeep(fileList)
var tabs = cloneDeep(tabList)
var active = null
files = files.filter((item) => item.route !== newRoute)
tabs = tabs.filter((item) => item.route !== newRoute)
files = files.map((item) => {
if (item.route === oldRoute) {
item.tab = rename
item.suffix = suffix === "yak" ? suffix : "http"
item.route = newRoute
return item
}
return item
})
tabs = tabs.map((item, index) => {
if (item.route === oldRoute) {
active = index
item.tab = rename
item.suffix = suffix === "yak" ? suffix : "http"
item.route = newRoute
return item
}
return item
})
if (active !== null) setActiveTab(`${active}`)
setFileList(files)
setTabList(tabs)
if (callback) callback()
})
}
)
const fileFunction = (kind: string, index: string, isFileList: boolean) => {
const tabCodeInfo = isFileList ? fileList[index] : tabList[index]
switch (kind) {
case "own":
closeCode(index, isFileList)
return
case "other":
const tabInfo: tabCodeProps = cloneDeep(tabList[index])
for (let i in tabList) {
if (i !== index && !tabList[i].isFile) {
const arr: tabCodeProps[] =
+i > +index
? [tabInfo].concat(tabList.splice(+i, tabList.length))
: tabList.splice(+i, tabList.length)
const num = +i > +index ? 1 : 0
setActiveTab(`${num}`)
setTabList(arr)
setHintFile(arr[num].tab)
setHintIndex(num)
setHintShow(true)
return
}
}
const code = cloneDeep(tabList[index])
setTabList([code])
setActiveTab(`0`)
return
case "all":
for (let i in tabList) {
if (!tabList[i].isFile) {
const arr = tabList.splice(+i, tabList.length)
setActiveTab("0")
setTabList(arr)
setHintFile(arr[0].tab)
setHintIndex(0)
setHintShow(true)
return
}
}
setActiveTab("")
setTabList([])
return
case "remove":
closeCode(index, isFileList)
return
case "delete":
delCode(index)
return
case "rename":
setRenameIndex(+index)
setRenameFlag(true)
setRenameCache(tabCodeInfo.tab)
return
}
}
const openFileLayout = (file: any) => {
addFile(file)
}
useEffect(() => {
ipcRenderer.invoke("fetch-code-path")
.then((path: string) => {
ipcRenderer.invoke("is-exists-file", path)
.then(() => {
setCodePath("")
})
.catch(() => {
setCodePath(path)
})
})
}, [])
useEffect(() => {
if (tabList.length === 0) setFullScreen(false)
}, [tabList])
useEffect(() => {
if (!xtermRef) {
return
}
// let buffer = "";
ipcRenderer.on("client-yak-error", async (e: any, data) => {
failed(`FoundError: ${JSON.stringify(data)}`)
if (typeof data === "object") {
setErrors([...errors, `${JSON.stringify(data)}`])
} else if (typeof data === "string") {
setErrors([...errors, data])
} else {
setErrors([...errors, `${data}`])
}
})
ipcRenderer.on("client-yak-end", () => {
info("Yak 代码执行完毕")
setTriggerForUpdatingHistory(getRandomInt(100000))
setTimeout(() => {
setExecuting(false)
}, 300)
})
ipcRenderer.on("client-yak-data", async (e: any, data: ExecResult) => {
if (data.IsMessage) {
// alert(Buffer.from(data.Message).toString("utf8"))
}
if (data?.Raw) {
writeExecResultXTerm(xtermRef, data, outputEncoding)
// writeXTerm(xtermRef, Buffer.from(data.Raw).toString(outputEncoding).replaceAll("\n", "\r\n"))
// monacoEditorWrite(currentOutputEditor, )
}
})
return () => {
ipcRenderer.removeAllListeners("client-yak-data")
ipcRenderer.removeAllListeners("client-yak-end")
ipcRenderer.removeAllListeners("client-yak-error")
}
}, [xtermRef])
const bars = (props: any, TabBarDefault: any) => {
return (
<TabBarDefault
{...props}
children={(barNode: React.ReactElement) => {
return (
<Dropdown
overlay={CustomMenu(barNode.key, false, tabMenu, fileFunction)}
trigger={["contextMenu"]}
>
{barNode}
</Dropdown>
)
}}
/>
)
}
return (
<AutoCard
className={"yak-executor-body"}
// title={"Yak Runner"}
headStyle={{minHeight: 0}}
bodyStyle={{padding: 0, overflow: "hidden"}}
>
<div
style={{width: "100%", height: "100%", display: "flex", backgroundColor: "#E8E9E8"}}
tabIndex={0}
onKeyDown={(e) => {
if (e.keyCode === 78 && (e.ctrlKey || e.metaKey)) {
newFile()
}
if (e.keyCode === 83 && (e.ctrlKey || e.metaKey) && activeTab) {
saveCode(tabList[+activeTab], +activeTab)
}
}}
>
<div style={{width: `${fullScreen ? 0 : 15}%`}}>
<AutoSpin spinning={loading}>
<ExecutorFileList
lists={fileList}
activeFile={tabList[+activeTab]?.route || ""}
renameFlag={renameFlag}
renameIndex={renameIndex}
renameCache={renameCache}
setRenameCache={setRenameCache}
addFile={addFile}
newFile={newFile}
openFile={openFileLayout}
fileFunction={fileFunction}
/>
</AutoSpin>
</div>
<div style={{width: `${fullScreen ? 100 : 85}%`}} className='executor-right-body'>
{tabList.length > 0 && (
<ResizeBox
isVer
firstNode={
<Tabs
className={"right-editor"}
style={{height: "100%"}}
type='editable-card'
activeKey={activeTab}
hideAdd={true}
onChange={(activeTab) => setActiveTab(activeTab)}
onEdit={(key, event: "add" | "remove") => {
switch (event) {
case "remove":
closeCode(key, false)
return
case "add":
return
}
}}
renderTabBar={(props, TabBarDefault) => {
return bars(props, TabBarDefault)
}}
tabBarExtraContent={
tabList.length && (
<Space style={{marginRight: 5}} size={0}>
<Button
style={{height: 25}}
type={"link"}
size={"small"}
disabled={
tabList[+activeTab] && tabList[+activeTab].suffix !== "yak"
}
onClick={(e) => {
let m = showDrawer({
width: "60%",
placement: "left",
title: "选择你的 Yak 模块执行特定功能",
content: (
<>
<YakScriptManagerPage
type={"yak"}
onLoadYakScript={(s) => {
const tab: tabCodeProps = {
tab: `Untitle-${unTitleCount}.yak`,
code: s.Content,
suffix: "yak",
isFile: false
}
info(`加载 Yak 模块:${s.ScriptName}`)
xtermClear(xtermRef)
setActiveTab(`${tabList.length}`)
setTabList(tabList.concat([tab]))
setUnTitleCount(unTitleCount + 1)
m.destroy()
}}
/>
</>
)
})
}}
>
Yak脚本模板
</Button>
<Button
icon={
fullScreen ? (
<FullscreenExitOutlined style={{fontSize: 15}} />
) : (
<FullscreenOutlined style={{fontSize: 15}} />
)
}
type={"link"}
size={"small"}
style={{width: 30, height: 25}}
onClick={() => setFullScreen(!fullScreen)}
/>
<Popover
trigger={["click"]}
title={"设置命令行额外参数"}
placement="bottomRight"
content={
<Space style={{width: 400}}>
<div>yak {tabList[+activeTab]?.tab || "[file]"}</div>
<Divider type={"vertical"} />
<Paragraph
style={{width: 200, marginBottom: 0}}
editable={{
icon: <Space>
<EditOutlined />
<SaveOutlined onClick={(e) => {
e.stopPropagation()
tabList[+activeTab].extraParams = extraParams
setTabList(tabList)
if(tabList[+activeTab].isFile){
const files = fileList.map(item => {
if(item.route === tabList[+activeTab].route){
item.extraParams = extraParams
return item
}
return item
})
setFileList(files)
}
success("保存成功")
}}
/></Space>,
tooltip: '编辑/保存为该文件默认参数',
onChange: setExtraParams
}}
>
{extraParams}
</Paragraph>
</Space>
}
>
<Button type={"link"} icon={<EllipsisOutlined />} onClick={() => {
setExtraParams(tabList[+activeTab]?.extraParams || "")
}} />
</Popover>
{executing ? (
<Button
icon={<PoweroffOutlined style={{fontSize: 15}} />}
type={"link"}
danger={true}
size={"small"}
style={{width: 30, height: 25}}
onClick={() => ipcRenderer.invoke("cancel-yak")}
/>
) : (
<Button
icon={<CaretRightOutlined style={{fontSize: 15}} />}
type={"link"}
ghost={true}
size={"small"}
style={{width: 30, height: 25}}
disabled={
tabList[+activeTab] && tabList[+activeTab].suffix !== "yak"
}
onClick={() => {
setErrors([])
setExecuting(true)
ipcRenderer.invoke("exec-yak", {
Script: tabList[+activeTab].code,
Params: [],
RunnerParamRaw: extraParams
})
}}
/>
)}
</Space>
)
}
>
{tabList.map((item, index) => {
return (
<TabPane tab={item.tab} key={`${index}`}>
<div style={{height: "100%"}}>
<AutoSpin spinning={executing}>
<div style={{height: "100%"}}>
<YakEditor
type={item.suffix}
value={item.code}
setValue={(value) => {
modifyCode(value, index)
}}
/>
</div>
</AutoSpin>
</div>
</TabPane>
)
})}
</Tabs>
}
firstRatio='70%'
secondNode={
<div
ref={xtermAsideRef}
style={{
width: "100%",
height: "100%",
overflow: "hidden",
borderTop: "1px solid #dfdfdf"
}}
>
<Tabs
style={{height: "100%"}}
className={"right-xterm"}
size={"small"}
tabBarExtraContent={
<Space>
<SelectOne
formItemStyle={{marginBottom: 0}}
value={outputEncoding}
setValue={setOutputEncoding}
size={"small"}
data={[
{text: "GBxxx编码", value: "latin1"},
{text: "UTF-8编码", value: "utf8"}
]}
/>
<Button
size={"small"}
icon={<DeleteOutlined />}
type={"link"}
onClick={(e) => {
xtermClear(xtermRef)
}}
/>
</Space>
}
>
<TabPane
tab={<div style={{width: 50, textAlign: "center"}}>输出</div>}
key={"output"}
>
<div style={{width: "100%", height: "100%"}}>
<CVXterm
ref={xtermRef}
options={{
convertEol: true,
theme: {
foreground: "#536870",
background: "#E8E9E8",
cursor: "#536870",
black: "#002831",
brightBlack: "#001e27",
red: "#d11c24",
brightRed: "#bd3613",
green: "#738a05",
brightGreen: "#475b62",
yellow: "#a57706",
brightYellow: "#536870",
blue: "#2176c7",
brightBlue: "#708284",
magenta: "#c61c6f",
brightMagenta: "#5956ba",
cyan: "#259286",
brightCyan: "#819090",
white: "#eae3cb",
brightWhite: "#fcf4dc"
}
}}
/>
</div>
</TabPane>
<TabPane
tab={
<div style={{width: 50, textAlign: "center"}} key={"terminal"}>
终端(监修中)
</div>
}
disabled
>
<Terminal />
</TabPane>
</Tabs>
</div>
}
secondRatio='30%'
/>
)}
{tabList.length === 0 && (
<Empty className='right-empty' description={<p>请点击左侧打开或新建文件</p>}></Empty>
)}
</div>
<Modal
visible={hintShow}
onCancel={() => setHintShow(false)}
footer={[
<Button key='link' onClick={() => setHintShow(false)}>
取消
</Button>,
<Button key='submit' onClick={() => ownCloseCode()}>
不保存
</Button>,
<Button key='back' type='primary' onClick={() => saveCode(tabList[hintIndex], hintIndex)}>
保存
</Button>
]}
>
<div style={{height: 40}}>
<ExclamationCircleOutlined style={{fontSize: 22, color: "#faad14"}} />
<span style={{fontSize: 18, marginLeft: 15}}>文件未保存</span>
</div>
<p style={{fontSize: 15, marginLeft: 37}}>{`是否要保存${hintFile}里面的内容吗?`}</p>
</Modal>
<Modal
visible={renameHint}
onCancel={() => setHintShow(false)}
footer={[
<Button key='link' onClick={() => setRenameHint(false)}>
取消
</Button>,
<Button
key='back'
type='primary'
onClick={() => {
const oldRoute = tabList[renameIndex].route
if (!oldRoute) return
const flagStr = oldRoute?.indexOf("/") > -1 ? "/" : "\\"
const routes = oldRoute?.split(flagStr)
routes?.pop()
const newRoute = routes?.concat([renameCache]).join(flagStr)
if (!oldRoute || !newRoute) return
renameFile(renameIndex, renameCache, oldRoute, newRoute, () => {
setRenameHint(false)
})
}}
>
确定
</Button>
]}
>
<div style={{height: 40}}>
<ExclamationCircleOutlined style={{fontSize: 22, color: "#faad14"}} />
<span style={{fontSize: 18, marginLeft: 15}}>文件已存在</span>
</div>
<p style={{fontSize: 15, marginLeft: 37}}>{`是否要覆盖已存在的文件吗?`}</p>
</Modal>
</div>
</AutoCard>
)
}