index.jsx 7.0 KB
Newer Older
J
Jason Park 已提交
1 2
import React from 'react';
import { connect } from 'react-redux';
3
import { withRouter } from 'react-router';
J
Jason Park 已提交
4
import AutosizeInput from 'react-input-autosize';
J
Jason Park 已提交
5
import screenfull from 'screenfull';
J
Jason Park 已提交
6
import Promise from 'bluebird';
J
Jason Park 已提交
7
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
J
Jason Park 已提交
8 9 10
import faAngleRight from '@fortawesome/fontawesome-free-solid/faAngleRight';
import faCaretDown from '@fortawesome/fontawesome-free-solid/faCaretDown';
import faCaretRight from '@fortawesome/fontawesome-free-solid/faCaretRight';
11
import faCodeBranch from '@fortawesome/fontawesome-free-solid/faCodeBranch';
J
Jason Park 已提交
12
import faExpandArrowsAlt from '@fortawesome/fontawesome-free-solid/faExpandArrowsAlt';
J
Jason Park 已提交
13
import faGithub from '@fortawesome/fontawesome-free-brands/faGithub';
J
Jason Park 已提交
14 15
import faTrashAlt from '@fortawesome/fontawesome-free-solid/faTrashAlt';
import faSave from '@fortawesome/fontawesome-free-solid/faSave';
J
Jason Park 已提交
16
import faFacebook from '@fortawesome/fontawesome-free-brands/faFacebook';
J
Jason Park 已提交
17
import faStar from '@fortawesome/fontawesome-free-solid/faStar';
J
Jason Park 已提交
18
import { GitHubApi } from '/apis';
J
Jason Park 已提交
19
import { classes, refineGist } from '/common/util';
J
Jason Park 已提交
20
import { actions } from '/reducers';
J
Jason Park 已提交
21
import { languages } from '/common/config';
J
Jason Park 已提交
22
import { BaseComponent, Button, Ellipsis, ListItem, Player } from '/components';
J
Jason Park 已提交
23 24
import styles from './stylesheet.scss';

25
@withRouter
J
Jason Park 已提交
26
@connect(({ current, env }) => ({ current, env }), actions)
J
Jason Park 已提交
27
class Header extends BaseComponent {
J
Jason Park 已提交
28 29 30 31 32 33 34 35 36 37
  handleClickFullScreen() {
    if (screenfull.enabled) {
      if (screenfull.isFullscreen) {
        screenfull.exit();
      } else {
        screenfull.request();
      }
    }
  }

J
Jason Park 已提交
38 39
  handleChangeTitle(e) {
    const { value } = e.target;
J
Jason Park 已提交
40
    this.props.modifyTitle(value);
J
Jason Park 已提交
41 42 43
  }

  saveGist() {
44
    const { user } = this.props.env;
45
    const { scratchPaper, titles, files, lastFiles } = this.props.current;
J
Jason Park 已提交
46
    const gist = {
47
      description: titles[titles.length - 1],
J
Jason Park 已提交
48
      files: {},
J
Jason Park 已提交
49 50 51 52 53 54
    };
    files.forEach(file => {
      gist.files[file.name] = {
        content: file.content,
      };
    });
J
Jason Park 已提交
55 56 57 58 59 60 61 62
    lastFiles.forEach(lastFile => {
      if (!(lastFile.name in gist.files)) {
        gist.files[lastFile.name] = null;
      }
    });
    gist.files['algorithm-visualizer'] = {
      content: 'https://algorithm-visualizer.org/',
    };
63 64
    const save = gist => {
      if (!user) return Promise.reject(new Error('Sign In Required'));
65 66 67 68 69 70
      if (scratchPaper && scratchPaper.login) {
        if (scratchPaper.login === user.login) {
          return GitHubApi.editGist(scratchPaper.gistId, gist);
        } else {
          return GitHubApi.forkGist(scratchPaper.gistId).then(forkedGist => GitHubApi.editGist(forkedGist.id, gist));
        }
71
      }
72
      return GitHubApi.createGist(gist);
73 74
    };
    save(gist)
J
Jason Park 已提交
75
      .then(refineGist)
76 77 78 79 80 81
      .then(newScratchPaper => {
        this.props.setScratchPaper(newScratchPaper);
        if (!(scratchPaper && scratchPaper.gistId === newScratchPaper.gistId)) {
          this.props.history.push(`/scratch-paper/${newScratchPaper.gistId}`);
        }
      })
82
      .then(this.props.loadScratchPapers)
J
Jason Park 已提交
83
      .catch(this.handleError);
J
Jason Park 已提交
84 85
  }

86 87 88 89 90 91 92 93 94 95 96
  hasPermission() {
    const { scratchPaper } = this.props.current;
    const { user } = this.props.env;
    if (!scratchPaper) return false;
    if (scratchPaper.gistId !== 'new') {
      if (!user) return false;
      if (scratchPaper.login !== user.login) return false;
    }
    return true;
  }

J
Jason Park 已提交
97
  deleteGist() {
J
Jason Park 已提交
98 99
    const { scratchPaper } = this.props.current;
    const { gistId } = scratchPaper;
100 101 102 103 104 105 106 107 108 109
    if (gistId === 'new') {
      this.props.markSaved();
      this.props.history.push('/');
    } else {
      GitHubApi.deleteGist(gistId)
        .then(() => {
          this.props.markSaved();
          this.props.history.push('/');
        })
        .then(this.props.loadScratchPapers)
J
Jason Park 已提交
110
        .catch(this.handleError);
111
    }
J
Jason Park 已提交
112 113
  }

J
Jason Park 已提交
114
  render() {
115 116
    const { className, onClickTitleBar, navigatorOpened, saved, file } = this.props;
    const { scratchPaper, titles } = this.props.current;
J
Jason Park 已提交
117
    const { ext, user } = this.props.env;
J
Jason Park 已提交
118

119 120
    const permitted = this.hasPermission();

J
Jason Park 已提交
121 122
    return (
      <header className={classes(styles.header, className)}>
J
Jason Park 已提交
123 124 125 126
        <div className={styles.row}>
          <div className={styles.section}>
            <Button className={styles.title_bar} onClick={onClickTitleBar}>
              {
127
                titles.map((title, i) => [
J
Jason Park 已提交
128
                  scratchPaper && i === 1 ?
J
Jason Park 已提交
129 130 131
                    <AutosizeInput className={styles.input_title} key={`title-${i}`} value={title}
                                   onClick={e => e.stopPropagation()} onChange={e => this.handleChangeTitle(e)} /> :
                    <Ellipsis key={`title-${i}`}>{title}</Ellipsis>,
132
                  i < titles.length - 1 &&
J
Jason Park 已提交
133 134 135 136 137 138
                  <FontAwesomeIcon className={styles.nav_arrow} fixedWidth icon={faAngleRight} key={`arrow-${i}`} />,
                ])
              }
              <FontAwesomeIcon className={styles.nav_caret} fixedWidth
                               icon={navigatorOpened ? faCaretDown : faCaretRight} />
            </Button>
J
Jason Park 已提交
139
          </div>
J
Jason Park 已提交
140
          <div className={styles.section}>
141 142 143 144 145 146 147
            <Button icon={permitted ? faSave : faCodeBranch} primary disabled={permitted && saved}
                    onClick={() => this.saveGist()}>{permitted ? 'Save' : 'Fork'}</Button>
            {
              permitted &&
              <Button icon={faTrashAlt} primary onClick={() => this.deleteGist()} confirmNeeded>Delete</Button>
            }
            <Button icon={faFacebook} primary
J
Jason Park 已提交
148
                    href={`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(window.location.href)}`}>Share</Button>
J
Jason Park 已提交
149 150 151 152 153 154 155
            <Button icon={faExpandArrowsAlt} primary
                    onClick={() => this.handleClickFullScreen()}>Fullscreen</Button>
          </div>
        </div>
        <div className={styles.row}>
          <div className={styles.section}>
            {
J
Jason Park 已提交
156 157 158
              user ?
                <Button className={styles.btn_dropdown} icon={user.avatar_url}>
                  {user.login}
J
Jason Park 已提交
159
                  <div className={styles.dropdown}>
160
                    <ListItem label="Sign Out" href="/api/auth/destroy" rel="nofollow" />
J
Jason Park 已提交
161 162
                  </div>
                </Button> :
163
                <Button icon={faGithub} primary href="/api/auth/request" rel="nofollow">
J
Jason Park 已提交
164 165 166 167 168 169
                  <Ellipsis>Sign In</Ellipsis>
                </Button>
            }
            <Button className={styles.btn_dropdown} icon={faStar}>
              {languages.find(language => language.ext === ext).name}
              <div className={styles.dropdown}>
J
Jason Park 已提交
170 171 172 173 174 175 176
                {
                  languages.map(language => language.ext === ext ? null : (
                    <ListItem key={language.ext} onClick={() => this.props.setExt(language.ext)}
                              label={language.name} />
                  ))
                }
              </div>
J
Jason Park 已提交
177 178
            </Button>
          </div>
179
          <Player className={styles.section} file={file} />
J
Jason Park 已提交
180 181 182 183 184 185 186 187
        </div>
      </header>
    );
  }
}

export default Header;