CoCalc Public Filessmc / src / smc-webapp / landing_page.cjsxOpen with one click!
Authors: J , John Kaltenbach, Varun Mahadevan, William A. Stein, Rebecca Yuen
Views : 52
Compute Environment: Ubuntu 18.04 (Deprecated)
1
{rclass, React, ReactDOM, redux, rtypes} = require('./smc-react')
2
{Alert, Button, ButtonToolbar, Col, Modal, Row, Input, Well} = require('react-bootstrap')
3
{ErrorDisplay, Icon, Loading, ImmutablePureRenderMixin, Footer, UNIT, SAGE_LOGO_COLOR, BS_BLUE_BGRND} = require('./r_misc')
4
{HelpEmailLink, SiteName, SiteDescription, TermsOfService, AccountCreationEmailInstructions} = require('./customize')
5
6
#DESC_FONT = "'Roboto Mono','monospace'"
7
DESC_FONT = 'sans-serif'
8
9
misc = require('smc-util/misc')
10
11
images = ['static/sagepreview/01-worksheet.png', 'static/sagepreview/02-courses.png', 'static/sagepreview/03-latex.png', 'static/sagepreview/05-sky_is_the_limit.png' ]
12
# 'static/sagepreview/04-files.png'
13
14
$.get window.smc_base_url + "/auth/strategies", (obj, status) ->
15
if status == 'success'
16
redux.getActions('account').setState(strategies : obj)
17
18
$.get window.smc_base_url + "/registration", (obj, status) ->
19
if status == 'success'
20
redux.getActions('account').setState(token : obj.token)
21
22
reset_password_key = () ->
23
url_args = window.location.href.split("#")
24
if url_args.length == 2 and url_args[1].slice(0, 6) == 'forgot'
25
return url_args[1].slice(7, 7+36)
26
return undefined
27
28
Passports = rclass
29
displayName : 'Passports'
30
31
propTypes :
32
strategies : rtypes.array
33
actions : rtypes.object.isRequired
34
35
styles :
36
facebook :
37
backgroundColor : "#395996"
38
color : "white"
39
google :
40
backgroundColor : "#DC4839"
41
color : "white"
42
twitter :
43
backgroundColor : "#55ACEE"
44
color : "white"
45
github :
46
backgroundColor : "black"
47
color : "black"
48
49
render_strategy : (name) ->
50
if name is 'email'
51
return
52
url = "#{window.smc_base_url}/auth/#{name}"
53
<a href={url} key={name}>
54
<Icon size='2x' name='stack' href={url}>
55
{<Icon name='circle' stack='2x' style={color: @styles[name].backgroundColor} /> if name isnt 'github'}
56
<Icon name={name} stack='1x' size={'2x' if name is 'github'} style={color: @styles[name].color} />
57
</Icon>
58
</a>
59
60
render : ->
61
<div style={textAlign: 'center'}>
62
<h3 style={marginTop: 0}>Connect with</h3>
63
<div>
64
{@render_strategy(name) for name in @props.strategies}
65
</div>
66
<hr style={marginTop: 10, marginBottom: 10} />
67
</div>
68
69
SignUp = rclass
70
displayName: 'SignUp'
71
72
propTypes :
73
strategies : rtypes.array
74
actions : rtypes.object.isRequired
75
sign_up_error : rtypes.object
76
token : rtypes.bool
77
has_account : rtypes.bool
78
signing_up : rtypes.bool
79
style : rtypes.object
80
81
make_account : (e) ->
82
e.preventDefault()
83
name = @refs.name.getValue()
84
email = @refs.email.getValue()
85
password = @refs.password.getValue()
86
token = @refs.token?.getValue()
87
@props.actions.create_account(name, email, password, token)
88
89
display_error : (field)->
90
if @props.sign_up_error?[field]?
91
<div style={color: "red", fontSize: "90%"}>{@props.sign_up_error[field]}</div>
92
93
display_passports : ->
94
if not @props.strategies?
95
return <Loading />
96
if @props.strategies.length > 1
97
return <Passports actions={@props.actions} strategies={@props.strategies} />
98
99
display_token_input : ->
100
if @props.token
101
<Input ref='token' type='text' placeholder='Enter the secret token' />
102
103
render : ->
104
<Well style={marginTop:'10px'}>
105
{@display_token_input()}
106
{@display_error("token")}
107
{@display_passports()}
108
<AccountCreationEmailInstructions />
109
<form style={marginTop: 20, marginBottom: 20} onSubmit={@make_account}>
110
{@display_error("first_name")}
111
<Input ref='name' type='text' autoFocus={not @props.has_account} placeholder='First and last Name' />
112
{@display_error("email_address")}
113
<Input ref='email' type='email' placeholder='Email address' />
114
{@display_error("password")}
115
<Input ref='password' type='password' placeholder='Choose a password' />
116
<TermsOfService style={fontSize: "small", textAlign: "center"} />
117
<Button style={marginBottom: UNIT, marginTop: UNIT}
118
disabled={@props.signing_up}
119
bsStyle="success"
120
bsSize='large'
121
type='submit'
122
block>
123
{<Icon name="spinner" spin /> if @props.signing_up} Sign up!
124
</Button>
125
</form>
126
<div style={textAlign: "center"}>
127
Email <HelpEmailLink /> if you need help.
128
</div>
129
</Well>
130
131
SignIn = rclass
132
displayName : "SignIn"
133
134
propTypes :
135
actions : rtypes.object.isRequired
136
sign_in_error : rtypes.string
137
signing_in : rtypes.bool
138
has_account : rtypes.bool
139
140
sign_in : (e) ->
141
e.preventDefault()
142
@props.actions.sign_in(@refs.email.getValue(), @refs.password.getValue())
143
144
display_forgot_password : ->
145
@props.actions.setState(show_forgot_password : true)
146
147
display_error : ->
148
if @props.sign_in_error?
149
<ErrorDisplay error={@props.sign_in_error} onClose={=>@props.actions.setState(sign_in_error: undefined)} />
150
151
remove_error : ->
152
if @props.sign_in_error
153
@props.actions.setState(sign_in_error : undefined)
154
155
render : ->
156
<Col sm=5>
157
<form onSubmit={@sign_in} className='form-inline' style={marginRight : 0, marginTop : 2 * UNIT}>
158
<Row>
159
<Col xs=5 style={paddingRight:'2px'}>
160
<Input style={marginRight: UNIT, width:'100%'} ref='email' type='email' placeholder='Email address' autoFocus={@props.has_account} onChange={@remove_error} />
161
</Col>
162
<Col xs=4 style={paddingLeft:'0px', paddingRight:'0px'}>
163
<Input style={marginRight: UNIT, width:'100%'} ref='password' type='password' placeholder='Password' onChange={@remove_error} />
164
</Col>
165
<Col xs=3 style={paddingLeft:'0px'}>
166
<Button type="submit" disabled={@props.signing_in} bsStyle="primary" className='pull-right'>Sign&nbsp;In</Button>
167
</Col>
168
</Row>
169
</form>
170
<Row>
171
<Col xs=7 xsOffset=5>
172
<a onClick={@display_forgot_password} style={cursor: "pointer", fontSize: '10pt', marginLeft: '-15px'} >Forgot Password?</a>
173
</Col>
174
</Row>
175
<Row className='form-inline pull-right' style={clear : "right"}>
176
<Col xs=12>
177
{@display_error()}
178
</Col>
179
</Row>
180
</Col>
181
182
ForgotPassword = rclass
183
displayName : "ForgotPassword"
184
185
mixins: [ImmutablePureRenderMixin]
186
187
propTypes :
188
actions : rtypes.object.isRequired
189
forgot_password_error : rtypes.string
190
forgot_password_success : rtypes.string
191
192
forgot_password : (e) ->
193
e.preventDefault()
194
@props.actions.forgot_password(@refs.email.getValue())
195
196
display_error : ->
197
if @props.forgot_password_error?
198
<span style={color: "red", fontSize: "90%"}>{@props.forgot_password_error}</span>
199
200
display_success : ->
201
if @props.forgot_password_success?
202
<span style={color: "green", fontSize: "90%"}>{@props.forgot_password_success}</span>
203
204
hide_forgot_password : ->
205
@props.actions.setState(show_forgot_password : false)
206
@props.actions.setState(forgot_password_error : undefined)
207
@props.actions.setState(forgot_password_success : undefined)
208
209
render : ->
210
<Modal show={true} onHide={@hide_forgot_password}>
211
<Modal.Body>
212
<div>
213
<h1>Forgot Password?</h1>
214
Enter your email address to reset your password
215
</div>
216
<form onSubmit={@forgot_password}>
217
{@display_error()}
218
{@display_success()}
219
<Input ref='email' type='email' placeholder='Email address' />
220
<hr />
221
Not working? Email us at <HelpEmailLink />
222
<Row>
223
<div style={textAlign: "right", paddingRight : 15}>
224
<Button type="submit" bsStyle="primary" bsSize="medium" style={marginRight : 10}>Reset Password</Button>
225
<Button onClick={@hide_forgot_password} bsSize="medium">Cancel</Button>
226
</div>
227
</Row>
228
</form>
229
</Modal.Body>
230
</Modal>
231
232
ResetPassword = rclass
233
propTypes : ->
234
actions : rtypes.object.isRequired
235
reset_key : rtypes.string.isRequired
236
reset_password_error : rtypes.string
237
238
mixins: [ImmutablePureRenderMixin]
239
240
reset_password : (e) ->
241
e.preventDefault()
242
@props.actions.reset_password(@props.reset_key, @refs.password.getValue())
243
244
hide_reset_password : (e) ->
245
e.preventDefault()
246
history.pushState("", document.title, window.location.pathname)
247
@props.actions.setState(reset_key : '', reset_password_error : '')
248
249
display_error : ->
250
if @props.reset_password_error
251
<span style={color: "red", fontSize: "90%"}>{@props.reset_password_error}</span>
252
253
render : ->
254
<Modal show={true} onHide={=>x=0}>
255
<Modal.Body>
256
<div>
257
<h1>Reset Password?</h1>
258
Enter your new password
259
</div>
260
<form onSubmit={@reset_password}>
261
<Input ref='password' type='password' placeholder='New Password' />
262
{@display_error()}
263
<hr />
264
Not working? Email us at <HelpEmailLink />
265
<Row>
266
<div style={textAlign: "right", paddingRight : 15}>
267
<Button type="submit" bsStyle="primary" bsSize="medium" style={marginRight : 10}>Reset password</Button>
268
<Button onClick={@hide_reset_password} bsSize="medium">Cancel</Button>
269
</div>
270
</Row>
271
</form>
272
</Modal.Body>
273
</Modal>
274
275
ContentItem = rclass
276
displayName: "ContentItem"
277
278
mixins: [ImmutablePureRenderMixin]
279
280
propTypes:
281
icon: rtypes.string.isRequired
282
heading: rtypes.string.isRequired
283
text: rtypes.string.isRequired
284
285
render : ->
286
<Row>
287
<Col sm=2>
288
<h1 style={textAlign: "center"}><Icon name={@props.icon} /></h1>
289
</Col>
290
<Col sm=10>
291
<h2 style={fontFamily: DESC_FONT}>{@props.heading}</h2>
292
{@props.text}
293
</Col>
294
</Row>
295
296
LANDING_PAGE_CONTENT =
297
teaching :
298
icon : 'university'
299
heading : 'Tools for Teaching'
300
text : 'Create projects for your students, hand out assignments, then collect and grade them with ease.'
301
collaboration :
302
icon : 'weixin'
303
heading : 'Collaboration Made Easy'
304
text : 'Edit documents with multiple team members in real time.'
305
programming :
306
icon : 'code'
307
heading : 'All-in-one Programming'
308
text : 'Write, compile and run code in nearly any programming language.'
309
math :
310
icon : 'area-chart'
311
heading : 'Computational Mathematics'
312
text : 'Use SageMath, IPython, the entire scientific Python stack, R, Julia, GAP, Octave and much more.'
313
latex :
314
icon : 'superscript'
315
heading : 'Built-in LaTeX Editor'
316
text : 'Write beautiful documents using LaTeX.'
317
318
SMC_Commercial = () ->
319
<iframe width="560" height="315" src="https://www.youtube.com/embed/AEKOjac9obk" frameBorder="0" allowFullScreen></iframe>
320
#<iframe src="https://player.vimeo.com/video/148146653?title=0&byline=0&portrait=0" width="600" height="337" frameBorder="0" allowFullScreen>
321
#</iframe>
322
323
LandingPageContent = rclass
324
displayName : 'LandingPageContent'
325
326
mixins: [ImmutablePureRenderMixin]
327
328
render : ->
329
<Well style={color:'#666'}>
330
{<ContentItem icon={v.icon} heading={v.heading} key={k} text={v.text} /> for k, v of LANDING_PAGE_CONTENT}
331
</Well>
332
333
SagePreview = rclass
334
displayName : "SagePreview"
335
336
render : ->
337
<div className="hidden-xs">
338
<Well>
339
<Row>
340
<Col sm=6>
341
<ExampleBox title="Interactive Worksheets" index={0}>
342
Interactively explore mathematics, science and statistics. <strong>Collaborate with others in real time</strong>. You can see their cursors moving around while they type &mdash; this works for Sage Worksheets and even Jupyter Notebooks!
343
</ExampleBox>
344
</Col>
345
<Col sm=6>
346
<ExampleBox title="Course Management" index={1}>
347
<SiteName /> helps to you to <strong>conveniently organize a course</strong>: add students, create their projects, see their progress,
348
understand their problems by dropping right into their files from wherever you are.
349
Conveniently handout assignments, collect them, grade them, and finally return them.
350
(<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>).
351
</ExampleBox>
352
</Col>
353
</Row>
354
<br />
355
<Row>
356
<Col sm=6>
357
<ExampleBox title="LaTeX Editor" index={2}>
358
<SiteName /> supports authoring documents written in LaTeX, Markdown or HTML.
359
The <strong>preview</strong> helps you understanding what&#39;s going on.
360
The LaTeX editor also supports <strong>forward and inverse search</strong> to avoid getting lost in large documents.
361
</ExampleBox>
362
</Col>
363
<Col sm=6>
364
<ExampleBox title="The Sky is the Limit" index={3}>
365
<SiteName /> does not arbitrarily restrict you. <strong>Upload</strong> your
366
own files, <strong>generate</strong> data and results online,
367
then download or <strong>publish</strong> your results.
368
Besides Sage Worksheets and Jupyter Notebooks,
369
you can work with a <strong>full Linux terminal</strong> and edit text with multiple cursors.
370
</ExampleBox>
371
</Col>
372
</Row>
373
</Well>
374
</div>
375
376
example_image_style =
377
border : '1px solid #aaa'
378
borderRadius : '3px'
379
padding : '5px'
380
background : 'white'
381
height : '236px'
382
383
ExampleBox = rclass
384
displayName : "ExampleBox"
385
386
propTypes :
387
title : rtypes.string.isRequired
388
index : rtypes.number.isRequired
389
390
render : ->
391
<div>
392
<h3 style={marginBottom:UNIT, fontFamily: DESC_FONT} >{@props.title}</h3>
393
<div style={marginBottom:'5px'} >
394
<img alt={@props.title} className = 'smc-grow-two' src="#{images[@props.index]}" style={example_image_style} />
395
</div>
396
<div>
397
{@props.children}
398
</div>
399
</div>
400
401
LogoWide = rclass
402
displayName: "LogoWide"
403
render : ->
404
<div style={fontSize: 3*UNIT,\
405
whiteSpace: 'nowrap',\
406
backgroundColor: SAGE_LOGO_COLOR,\
407
borderRadius : 4,\
408
display: 'inline-block',\
409
padding: 1,\
410
margin: UNIT + 'px 0',\
411
lineHeight: 0}>
412
<span style={display: 'inline-block', \
413
backgroundImage: 'url("/static/salvus-icon.svg")', \
414
backgroundSize: 'contain', \
415
height : UNIT * 4, width: UNIT * 4, \
416
borderRadius : 10, \
417
verticalAlign: 'center'}>
418
</span>
419
<div className="hidden-sm"
420
style={display:'inline-block',\
421
fontFamily: DESC_FONT,\
422
top: -1 * UNIT,\
423
position: 'relative',\
424
color: 'white',\
425
paddingRight: UNIT}><SiteName /></div>
426
</div>
427
428
RememberMe = () ->
429
<div style={fontSize : "35px", marginTop: "125px", textAlign: "center", color: "#888"}>
430
<Icon name="spinner" spin /> Signing you in...
431
</div>
432
433
434
exports.LandingPage = rclass
435
propTypes:
436
actions : rtypes.object.isRequired
437
strategies : rtypes.array
438
sign_up_error : rtypes.object
439
sign_in_error : rtypes.string
440
signing_in : rtypes.bool
441
signing_up : rtypes.bool
442
forgot_password_error : rtypes.string
443
forgot_password_success : rtypes.string #is this needed?
444
show_forgot_password : rtypes.bool
445
token : rtypes.bool
446
reset_key : rtypes.string
447
reset_password_error : rtypes.string
448
remember_me : rtypes.bool
449
has_account : rtypes.bool
450
451
render : ->
452
if not @props.remember_me
453
reset_key = reset_password_key()
454
<div style={marginLeft: 20, marginRight: 20}>
455
{<ResetPassword reset_key={reset_key}
456
reset_password_error={@props.reset_password_error}
457
actions={@props.actions} /> if reset_key}
458
{<ForgotPassword actions={@props.actions}
459
forgot_password_error={@props.forgot_password_error}
460
forgot_password_success={@props.forgot_password_success} /> if @props.show_forgot_password}
461
<Row>
462
<Col sm=12>
463
<Row>
464
<Col sm=7 className="hidden-xs">
465
<LogoWide />
466
</Col>
467
<SignIn actions={@props.actions}
468
signing_in={@props.signing_in}
469
sign_in_error={@props.sign_in_error}
470
has_account={@props.has_account} />
471
</Row>
472
<Row className="hidden-xs">
473
<Col sm=12>
474
<SiteDescription />
475
</Col>
476
</Row>
477
</Col>
478
</Row>
479
<Row>
480
<Col sm=7 className="hidden-xs" style=marginTop:'10px'>
481
<SMC_Commercial />
482
</Col>
483
<Col sm=5>
484
<SignUp actions={@props.actions}
485
sign_up_error={@props.sign_up_error}
486
strategies={@props.strategies}
487
token={@props.token}
488
signing_up={@props.signing_up}
489
has_account={@props.has_account} />
490
</Col>
491
</Row>
492
<Row>
493
<Col sm=12 className='hidden-xs'>
494
<LandingPageContent />
495
</Col>
496
</Row>
497
<SagePreview />
498
<Footer/>
499
</div>
500
else
501
<RememberMe />
502