[ReactNavToolbar] Integration branch (#3513)

* Created ng-controller for react shared context and set editor.loading

* toolbar-header component with menu button (and story)

* Added editor-navigation-toolbar-root and react2angular plumbing

* Added eslint-disable exception to use <a/> instead of <button/>

* added 'menu' to extracted translation

* [ReactNavToolbar] Added cobranding and back to projects buttons (#3515)

GitOrigin-RevId: 27c3bba85cbc96a123d58c66a0bd5d6a2cfd8aca
This commit is contained in:
Miguel Serrano 2021-01-27 11:30:55 +01:00 committed by Copybot
parent 0d57ddfd23
commit 37d45d64b3
15 changed files with 199 additions and 14 deletions

View file

@ -833,6 +833,8 @@ const ProjectController = {
wsUrl,
showSupport: Features.hasFeature('support'),
showNewLogsUI: user.alphaProgram && !wantsOldLogsUI,
showNewNavigationUI:
req.query && req.query.new_navigation_ui === 'true',
showReactFileTree: user.betaProgram && !wantsOldFileTreeUI
})
timer.done()

View file

@ -8,7 +8,10 @@ block vars
block content
.editor(ng-controller="IdeController").full-size
//- required by react2angular-shared-context, must be rendered as a top level component
shared-context-react()
div(
ng-controller="ReactRootContextController"
)
shared-context-react(editor-loading="editorLoading")
.loading-screen(ng-if="state.loading")
.loading-screen-brand-container
.loading-screen-brand(
@ -74,7 +77,10 @@ block content
ng-cloak
)
.ui-layout-center
include ./editor/header
if showNewNavigationUI
include ./editor/header-react
else
include ./editor/header
include ./editor/share
!= moduleIncludes("publish:body", locals)

View file

@ -0,0 +1,3 @@
div(ng-controller="EditorNavigationToolbarController")
editor-navigation-toolbar-root(on-show-left-menu-click="onShowLeftMenuClick")

View file

@ -5,6 +5,7 @@
"autocompile_disabled_reason",
"autocomplete",
"autocomplete_references",
"back_to_your_projects",
"blocked_filename",
"cancel",
"clear_cached_files",
@ -67,6 +68,7 @@
"main_file_not_found",
"math_display",
"math_inline",
"menu",
"n_errors",
"n_errors_plural",
"n_items",

View file

@ -0,0 +1,18 @@
import React from 'react'
import Icon from '../../../shared/components/icon'
import { useTranslation } from 'react-i18next'
function BackToProjectsButton() {
const { t } = useTranslation()
return (
<a className="toolbar-header-back-projects" href="/project">
<Icon
type="fw"
modifier="level-up"
accessibilityLabel={t('back_to_your_projects')}
/>
</a>
)
}
export default BackToProjectsButton

View file

@ -0,0 +1,31 @@
import React from 'react'
import PropTypes from 'prop-types'
function CobrandingLogo({
brandVariationHomeUrl,
brandVariationName,
logoImgUrl
}) {
return (
<a
className="btn btn-full-height header-cobranding-logo-container"
href={brandVariationHomeUrl}
target="_blank"
rel="noreferrer noopener"
>
<img
src={logoImgUrl}
className="header-cobranding-logo"
alt={brandVariationName}
/>
</a>
)
}
CobrandingLogo.propTypes = {
brandVariationHomeUrl: PropTypes.string.isRequired,
brandVariationName: PropTypes.string.isRequired,
logoImgUrl: PropTypes.string.isRequired
}
export default CobrandingLogo

View file

@ -0,0 +1,23 @@
import React from 'react'
import PropTypes from 'prop-types'
import ToolbarHeader from './toolbar-header'
import { useEditorContext } from '../../../shared/context/editor-context'
function EditorNavigationToolbarRoot({ onShowLeftMenuClick }) {
const { cobranding, loading } = useEditorContext()
// using {display: 'none'} as 1:1 migration from Angular's ng-hide. Using
// `loading ? null : <ToolbarHeader/>` causes UI glitches
return (
<ToolbarHeader
style={loading ? { display: 'none' } : {}}
cobranding={cobranding}
onShowLeftMenuClick={onShowLeftMenuClick}
/>
)
}
EditorNavigationToolbarRoot.propTypes = {
onShowLeftMenuClick: PropTypes.func.isRequired
}
export default EditorNavigationToolbarRoot

View file

@ -0,0 +1,22 @@
import React from 'react'
import PropTypes from 'prop-types'
import { useTranslation } from 'react-i18next'
import Icon from '../../../shared/components/icon'
function MenuButton({ onClick }) {
const { t } = useTranslation()
return (
// eslint-disable-next-line jsx-a11y/anchor-is-valid
<a role="button" className="btn btn-full-height" href="#" onClick={onClick}>
<Icon type="fw" modifier="bars" classes={{ icon: 'editor-menu-icon' }} />
<p className="toolbar-label">{t('menu')}</p>
</a>
)
}
MenuButton.propTypes = {
onClick: PropTypes.func.isRequired
}
export default MenuButton

View file

@ -0,0 +1,24 @@
import React from 'react'
import PropTypes from 'prop-types'
import MenuButton from './menu-button'
import CobrandingLogo from './cobranding-logo'
import BackToProjectsButton from './back-to-projects-button'
function ToolbarHeader({ cobranding, onShowLeftMenuClick }) {
return (
<header className="toolbar toolbar-header toolbar-with-labels">
<div className="toolbar-left">
<MenuButton onClick={onShowLeftMenuClick} />
{cobranding ? <CobrandingLogo {...cobranding} /> : null}
<BackToProjectsButton />
</div>
</header>
)
}
ToolbarHeader.propTypes = {
onShowLeftMenuClick: PropTypes.func.isRequired,
cobranding: PropTypes.object
}
export default ToolbarHeader

View file

@ -0,0 +1,18 @@
import App from '../../../base'
import { react2angular } from 'react2angular'
import EditorNavigationToolbarRoot from '../components/editor-navigation-toolbar-root'
import { rootContext } from '../../../shared/context/root-context'
App.controller('EditorNavigationToolbarController', function($scope, ide) {
$scope.onShowLeftMenuClick = () =>
ide.$scope.$applyAsync(() => {
ide.$scope.ui.leftMenuShown = !ide.$scope.ui.leftMenuShown
})
})
App.component(
'editorNavigationToolbarRoot',
react2angular(rootContext.use(EditorNavigationToolbarRoot), [
'onShowLeftMenuClick'
])
)

View file

@ -61,9 +61,8 @@ import './main/account-upgrade-angular'
import './main/exposed-settings-angular'
import './main/system-messages'
import '../../modules/modules-ide.js'
import { react2angular } from 'react2angular'
import { rootContext } from './shared/context/root-context'
import './shared/context/controllers/root-context-controller'
import './features/editor-navigation-toolbar/controllers/editor-navigation-toolbar-controller'
App.controller('IdeController', function(
$scope,
@ -353,10 +352,6 @@ If the project has been renamed please look in your project list for a new proje
})
})
// required by react2angular-shared-context, maps the shared context instance to an angular component
// that must be rendered in the app
App.component('sharedContextReact', react2angular(rootContext.component))
export default angular.bootstrap(document.body, ['SharelatexApp'])
function __guard__(value, transform) {

View file

@ -0,0 +1,15 @@
import App from '../../../base'
import { react2angular } from 'react2angular'
import { rootContext } from '../root-context'
App.controller('ReactRootContextController', function($scope, ide) {
$scope.editorLoading = !!ide.$scope.state.loading
ide.$scope.$watch('state.loading', editorLoading => {
$scope.editorLoading = editorLoading
})
})
App.component(
'sharedContextReact',
react2angular(rootContext.component, ['editorLoading'])
)

View file

@ -3,13 +3,23 @@ import PropTypes from 'prop-types'
export const EditorContext = createContext()
export function EditorProvider({ children }) {
export function EditorProvider({ children, loading }) {
const cobranding = window.brandVariation
? {
logoImgUrl: window.brandVariation.logo_url,
brandVariationName: window.brandVariation.name,
brandVariationHomeUrl: window.brandVariation.home_url
}
: undefined
const ownerId =
window._ide.$scope.project && window._ide.$scope.project.owner
? window._ide.$scope.project.owner._id
: null
const editorContextValue = {
cobranding,
loading,
projectId: window.project_id,
isProjectOwner: ownerId === window.user.id
}
@ -22,7 +32,8 @@ export function EditorProvider({ children }) {
}
EditorProvider.propTypes = {
children: PropTypes.any
children: PropTypes.any,
loading: PropTypes.bool
}
export function useEditorContext() {

View file

@ -1,15 +1,20 @@
import React from 'react'
import PropTypes from 'prop-types'
import { ApplicationProvider } from './application-context'
import { EditorProvider } from './editor-context'
import createSharedContext from 'react2angular-shared-context'
// eslint-disable-next-line react/prop-types
export function ContextRoot({ children }) {
export function ContextRoot({ children, editorLoading }) {
return (
<ApplicationProvider>
<EditorProvider>{children}</EditorProvider>
<EditorProvider loading={editorLoading}>{children}</EditorProvider>
</ApplicationProvider>
)
}
ContextRoot.propTypes = {
children: PropTypes.any,
editorLoading: PropTypes.bool
}
export const rootContext = createSharedContext(ContextRoot)

View file

@ -0,0 +1,10 @@
import React from 'react'
import ToolbarHeader from '../js/features/editor-navigation-toolbar/components/toolbar-header'
export const Default = () => {
return <ToolbarHeader />
}
export default {
title: 'EditorNavigationToolbar'
}