Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
| Download
Project: jrv
Views: 155{rclass, React, ReactDOM, redux, rtypes} = require('./smc-react')1{Alert, Button, ButtonToolbar, Col, Modal, Row, Input, Well} = require('react-bootstrap')2{ErrorDisplay, Icon, Loading, ImmutablePureRenderMixin, Footer, UNIT, SAGE_LOGO_COLOR, BS_BLUE_BGRND} = require('./r_misc')3{HelpEmailLink, SiteName, SiteDescription, TermsOfService, AccountCreationEmailInstructions} = require('./customize')45#DESC_FONT = "'Roboto Mono','monospace'"6DESC_FONT = 'sans-serif'78misc = require('smc-util/misc')910images = ['static/sagepreview/01-worksheet.png', 'static/sagepreview/02-courses.png', 'static/sagepreview/03-latex.png', 'static/sagepreview/05-sky_is_the_limit.png' ]11# 'static/sagepreview/04-files.png'1213$.get window.smc_base_url + "/auth/strategies", (obj, status) ->14if status == 'success'15redux.getActions('account').setState(strategies : obj)1617$.get window.smc_base_url + "/registration", (obj, status) ->18if status == 'success'19redux.getActions('account').setState(token : obj.token)2021reset_password_key = () ->22url_args = window.location.href.split("#")23if url_args.length == 2 and url_args[1].slice(0, 6) == 'forgot'24return url_args[1].slice(7, 7+36)25return undefined2627Passports = rclass28displayName : 'Passports'2930propTypes :31strategies : rtypes.array32actions : rtypes.object.isRequired3334styles :35facebook :36backgroundColor : "#395996"37color : "white"38google :39backgroundColor : "#DC4839"40color : "white"41twitter :42backgroundColor : "#55ACEE"43color : "white"44github :45backgroundColor : "black"46color : "black"4748render_strategy : (name) ->49if name is 'email'50return51url = "#{window.smc_base_url}/auth/#{name}"52<a href={url} key={name}>53<Icon size='2x' name='stack' href={url}>54{<Icon name='circle' stack='2x' style={color: @styles[name].backgroundColor} /> if name isnt 'github'}55<Icon name={name} stack='1x' size={'2x' if name is 'github'} style={color: @styles[name].color} />56</Icon>57</a>5859render : ->60<div style={textAlign: 'center'}>61<h3 style={marginTop: 0}>Connect with</h3>62<div>63{@render_strategy(name) for name in @props.strategies}64</div>65<hr style={marginTop: 10, marginBottom: 10} />66</div>6768SignUp = rclass69displayName: 'SignUp'7071propTypes :72strategies : rtypes.array73actions : rtypes.object.isRequired74sign_up_error : rtypes.object75token : rtypes.bool76has_account : rtypes.bool77signing_up : rtypes.bool78style : rtypes.object7980make_account : (e) ->81e.preventDefault()82name = @refs.name.getValue()83email = @refs.email.getValue()84password = @refs.password.getValue()85token = @refs.token?.getValue()86@props.actions.create_account(name, email, password, token)8788display_error : (field)->89if @props.sign_up_error?[field]?90<div style={color: "red", fontSize: "90%"}>{@props.sign_up_error[field]}</div>9192display_passports : ->93if not @props.strategies?94return <Loading />95if @props.strategies.length > 196return <Passports actions={@props.actions} strategies={@props.strategies} />9798display_token_input : ->99if @props.token100<Input ref='token' type='text' placeholder='Enter the secret token' />101102render : ->103<Well style={marginTop:'10px'}>104{@display_token_input()}105{@display_error("token")}106{@display_passports()}107<AccountCreationEmailInstructions />108<form style={marginTop: 20, marginBottom: 20} onSubmit={@make_account}>109{@display_error("first_name")}110<Input ref='name' type='text' autoFocus={not @props.has_account} placeholder='First and last Name' />111{@display_error("email_address")}112<Input ref='email' type='email' placeholder='Email address' />113{@display_error("password")}114<Input ref='password' type='password' placeholder='Choose a password' />115<TermsOfService style={fontSize: "small", textAlign: "center"} />116<Button style={marginBottom: UNIT, marginTop: UNIT}117disabled={@props.signing_up}118bsStyle="success"119bsSize='large'120type='submit'121block>122{<Icon name="spinner" spin /> if @props.signing_up} Sign up!123</Button>124</form>125<div style={textAlign: "center"}>126Email <HelpEmailLink /> if you need help.127</div>128</Well>129130SignIn = rclass131displayName : "SignIn"132133propTypes :134actions : rtypes.object.isRequired135sign_in_error : rtypes.string136signing_in : rtypes.bool137has_account : rtypes.bool138139sign_in : (e) ->140e.preventDefault()141@props.actions.sign_in(@refs.email.getValue(), @refs.password.getValue())142143display_forgot_password : ->144@props.actions.setState(show_forgot_password : true)145146display_error : ->147if @props.sign_in_error?148<ErrorDisplay error={@props.sign_in_error} onClose={=>@props.actions.setState(sign_in_error: undefined)} />149150remove_error : ->151if @props.sign_in_error152@props.actions.setState(sign_in_error : undefined)153154render : ->155<Col sm=5>156<form onSubmit={@sign_in} className='form-inline' style={marginRight : 0, marginTop : 2 * UNIT}>157<Row>158<Col xs=5 style={paddingRight:'2px'}>159<Input style={marginRight: UNIT, width:'100%'} ref='email' type='email' placeholder='Email address' autoFocus={@props.has_account} onChange={@remove_error} />160</Col>161<Col xs=4 style={paddingLeft:'0px', paddingRight:'0px'}>162<Input style={marginRight: UNIT, width:'100%'} ref='password' type='password' placeholder='Password' onChange={@remove_error} />163</Col>164<Col xs=3 style={paddingLeft:'0px'}>165<Button type="submit" disabled={@props.signing_in} bsStyle="primary" className='pull-right'>Sign In</Button>166</Col>167</Row>168</form>169<Row>170<Col xs=7 xsOffset=5>171<a onClick={@display_forgot_password} style={cursor: "pointer", fontSize: '10pt', marginLeft: '-15px'} >Forgot Password?</a>172</Col>173</Row>174<Row className='form-inline pull-right' style={clear : "right"}>175<Col xs=12>176{@display_error()}177</Col>178</Row>179</Col>180181ForgotPassword = rclass182displayName : "ForgotPassword"183184mixins: [ImmutablePureRenderMixin]185186propTypes :187actions : rtypes.object.isRequired188forgot_password_error : rtypes.string189forgot_password_success : rtypes.string190191forgot_password : (e) ->192e.preventDefault()193@props.actions.forgot_password(@refs.email.getValue())194195display_error : ->196if @props.forgot_password_error?197<span style={color: "red", fontSize: "90%"}>{@props.forgot_password_error}</span>198199display_success : ->200if @props.forgot_password_success?201<span style={color: "green", fontSize: "90%"}>{@props.forgot_password_success}</span>202203hide_forgot_password : ->204@props.actions.setState(show_forgot_password : false)205@props.actions.setState(forgot_password_error : undefined)206@props.actions.setState(forgot_password_success : undefined)207208render : ->209<Modal show={true} onHide={@hide_forgot_password}>210<Modal.Body>211<div>212<h1>Forgot Password?</h1>213Enter your email address to reset your password214</div>215<form onSubmit={@forgot_password}>216{@display_error()}217{@display_success()}218<Input ref='email' type='email' placeholder='Email address' />219<hr />220Not working? Email us at <HelpEmailLink />221<Row>222<div style={textAlign: "right", paddingRight : 15}>223<Button type="submit" bsStyle="primary" bsSize="medium" style={marginRight : 10}>Reset Password</Button>224<Button onClick={@hide_forgot_password} bsSize="medium">Cancel</Button>225</div>226</Row>227</form>228</Modal.Body>229</Modal>230231ResetPassword = rclass232propTypes : ->233actions : rtypes.object.isRequired234reset_key : rtypes.string.isRequired235reset_password_error : rtypes.string236237mixins: [ImmutablePureRenderMixin]238239reset_password : (e) ->240e.preventDefault()241@props.actions.reset_password(@props.reset_key, @refs.password.getValue())242243hide_reset_password : (e) ->244e.preventDefault()245history.pushState("", document.title, window.location.pathname)246@props.actions.setState(reset_key : '', reset_password_error : '')247248display_error : ->249if @props.reset_password_error250<span style={color: "red", fontSize: "90%"}>{@props.reset_password_error}</span>251252render : ->253<Modal show={true} onHide={=>x=0}>254<Modal.Body>255<div>256<h1>Reset Password?</h1>257Enter your new password258</div>259<form onSubmit={@reset_password}>260<Input ref='password' type='password' placeholder='New Password' />261{@display_error()}262<hr />263Not working? Email us at <HelpEmailLink />264<Row>265<div style={textAlign: "right", paddingRight : 15}>266<Button type="submit" bsStyle="primary" bsSize="medium" style={marginRight : 10}>Reset password</Button>267<Button onClick={@hide_reset_password} bsSize="medium">Cancel</Button>268</div>269</Row>270</form>271</Modal.Body>272</Modal>273274ContentItem = rclass275displayName: "ContentItem"276277mixins: [ImmutablePureRenderMixin]278279propTypes:280icon: rtypes.string.isRequired281heading: rtypes.string.isRequired282text: rtypes.string.isRequired283284render : ->285<Row>286<Col sm=2>287<h1 style={textAlign: "center"}><Icon name={@props.icon} /></h1>288</Col>289<Col sm=10>290<h2 style={fontFamily: DESC_FONT}>{@props.heading}</h2>291{@props.text}292</Col>293</Row>294295LANDING_PAGE_CONTENT =296teaching :297icon : 'university'298heading : 'Tools for Teaching'299text : 'Create projects for your students, hand out assignments, then collect and grade them with ease.'300collaboration :301icon : 'weixin'302heading : 'Collaboration Made Easy'303text : 'Edit documents with multiple team members in real time.'304programming :305icon : 'code'306heading : 'All-in-one Programming'307text : 'Write, compile and run code in nearly any programming language.'308math :309icon : 'area-chart'310heading : 'Computational Mathematics'311text : 'Use SageMath, IPython, the entire scientific Python stack, R, Julia, GAP, Octave and much more.'312latex :313icon : 'superscript'314heading : 'Built-in LaTeX Editor'315text : 'Write beautiful documents using LaTeX.'316317SMC_Commercial = () ->318<iframe width="560" height="315" src="https://www.youtube.com/embed/AEKOjac9obk" frameBorder="0" allowFullScreen></iframe>319#<iframe src="https://player.vimeo.com/video/148146653?title=0&byline=0&portrait=0" width="600" height="337" frameBorder="0" allowFullScreen>320#</iframe>321322LandingPageContent = rclass323displayName : 'LandingPageContent'324325mixins: [ImmutablePureRenderMixin]326327render : ->328<Well style={color:'#666'}>329{<ContentItem icon={v.icon} heading={v.heading} key={k} text={v.text} /> for k, v of LANDING_PAGE_CONTENT}330</Well>331332SagePreview = rclass333displayName : "SagePreview"334335render : ->336<div className="hidden-xs">337<Well>338<Row>339<Col sm=6>340<ExampleBox title="Interactive Worksheets" index={0}>341Interactively explore mathematics, science and statistics. <strong>Collaborate with others in real time</strong>. You can see their cursors moving around while they type — this works for Sage Worksheets and even Jupyter Notebooks!342</ExampleBox>343</Col>344<Col sm=6>345<ExampleBox title="Course Management" index={1}>346<SiteName /> helps to you to <strong>conveniently organize a course</strong>: add students, create their projects, see their progress,347understand their problems by dropping right into their files from wherever you are.348Conveniently handout assignments, collect them, grade them, and finally return them.349(<a href="https://github.com/sagemathinc/smc/wiki/Teaching" target="_blank">SMC used for Teaching</a> and <a href="http://www.beezers.org/blog/bb/2015/09/grading-in-sagemathcloud/" target="_blank">learn more about courses</a>).350</ExampleBox>351</Col>352</Row>353<br />354<Row>355<Col sm=6>356<ExampleBox title="LaTeX Editor" index={2}>357<SiteName /> supports authoring documents written in LaTeX, Markdown or HTML.358The <strong>preview</strong> helps you understanding what's going on.359The LaTeX editor also supports <strong>forward and inverse search</strong> to avoid getting lost in large documents.360</ExampleBox>361</Col>362<Col sm=6>363<ExampleBox title="The Sky is the Limit" index={3}>364<SiteName /> does not arbitrarily restrict you. <strong>Upload</strong> your365own files, <strong>generate</strong> data and results online,366then download or <strong>publish</strong> your results.367Besides Sage Worksheets and Jupyter Notebooks,368you can work with a <strong>full Linux terminal</strong> and edit text with multiple cursors.369</ExampleBox>370</Col>371</Row>372</Well>373</div>374375example_image_style =376border : '1px solid #aaa'377borderRadius : '3px'378padding : '5px'379background : 'white'380height : '236px'381382ExampleBox = rclass383displayName : "ExampleBox"384385propTypes :386title : rtypes.string.isRequired387index : rtypes.number.isRequired388389render : ->390<div>391<h3 style={marginBottom:UNIT, fontFamily: DESC_FONT} >{@props.title}</h3>392<div style={marginBottom:'5px'} >393<img alt={@props.title} className = 'smc-grow-two' src="#{images[@props.index]}" style={example_image_style} />394</div>395<div>396{@props.children}397</div>398</div>399400LogoWide = rclass401displayName: "LogoWide"402render : ->403<div style={fontSize: 3*UNIT,\404whiteSpace: 'nowrap',\405backgroundColor: SAGE_LOGO_COLOR,\406borderRadius : 4,\407display: 'inline-block',\408padding: 1,\409margin: UNIT + 'px 0',\410lineHeight: 0}>411<span style={display: 'inline-block', \412backgroundImage: 'url("/static/salvus-icon.svg")', \413backgroundSize: 'contain', \414height : UNIT * 4, width: UNIT * 4, \415borderRadius : 10, \416verticalAlign: 'center'}>417</span>418<div className="hidden-sm"419style={display:'inline-block',\420fontFamily: DESC_FONT,\421top: -1 * UNIT,\422position: 'relative',\423color: 'white',\424paddingRight: UNIT}><SiteName /></div>425</div>426427RememberMe = () ->428<div style={fontSize : "35px", marginTop: "125px", textAlign: "center", color: "#888"}>429<Icon name="spinner" spin /> Signing you in...430</div>431432433exports.LandingPage = rclass434propTypes:435actions : rtypes.object.isRequired436strategies : rtypes.array437sign_up_error : rtypes.object438sign_in_error : rtypes.string439signing_in : rtypes.bool440signing_up : rtypes.bool441forgot_password_error : rtypes.string442forgot_password_success : rtypes.string #is this needed?443show_forgot_password : rtypes.bool444token : rtypes.bool445reset_key : rtypes.string446reset_password_error : rtypes.string447remember_me : rtypes.bool448has_account : rtypes.bool449450render : ->451if not @props.remember_me452reset_key = reset_password_key()453<div style={marginLeft: 20, marginRight: 20}>454{<ResetPassword reset_key={reset_key}455reset_password_error={@props.reset_password_error}456actions={@props.actions} /> if reset_key}457{<ForgotPassword actions={@props.actions}458forgot_password_error={@props.forgot_password_error}459forgot_password_success={@props.forgot_password_success} /> if @props.show_forgot_password}460<Row>461<Col sm=12>462<Row>463<Col sm=7 className="hidden-xs">464<LogoWide />465</Col>466<SignIn actions={@props.actions}467signing_in={@props.signing_in}468sign_in_error={@props.sign_in_error}469has_account={@props.has_account} />470</Row>471<Row className="hidden-xs">472<Col sm=12>473<SiteDescription />474</Col>475</Row>476</Col>477</Row>478<Row>479<Col sm=7 className="hidden-xs" style=marginTop:'10px'>480<SMC_Commercial />481</Col>482<Col sm=5>483<SignUp actions={@props.actions}484sign_up_error={@props.sign_up_error}485strategies={@props.strategies}486token={@props.token}487signing_up={@props.signing_up}488has_account={@props.has_account} />489</Col>490</Row>491<Row>492<Col sm=12 className='hidden-xs'>493<LandingPageContent />494</Col>495</Row>496<SagePreview />497<Footer/>498</div>499else500<RememberMe />501502503