<div id="root" />
@import url('https://fonts.googleapis.com/css?family=Cabin|Old+Standard+TT');
html, body {/*  */
  font-family: 'Old Standard TT', serif; 
  font-size: 1em;
  height: 100%;
}
#root,#root div {/*  */
  /* height: 90%;*/
}
h1,h2,h3,h4,h5 {/*  */
 font-family: 'Cabin', sans-serif;
}
.tab-container{/*  */
  display:flex;
}
.tab .tab-title{/*  */
  cursor: pointer;
}
.tab .tab-title h2{
  margin-top: 0;
}
.tab.collapsed{
  border-right: 1px solid #EEEEEE;
  border-left: 1px solid #EEEEEE;
  color: #757575;
}
.tab:not(.collapsed){/*  */
  color: inherit;
  padding-left: 1rem;
  width: 100%;
}
.tab:not(.collapsed) .tab-title{/*  */
  margin-top: 0;
  /*transform: rotate(0deg);*/
  /*transition: transform 0.5s ease;*/
}

.tab.collapsed .tab-title{ 
  transform: rotate(90deg);
  transition: transform 0.5s ease;
  /*animation-name: rotatetab;*/
  /*  animation-duration: 1s;*/
}

.tab.collapsed .tab-content, .tab.tab-search.collapsed .tab-content{/*  */
    display: none;
}
.tab .tab-content{/*  */
    width: 100%;
}
.tab.collapsed .tab-content{ display: none; }

.tab.tab-search .tab-content{/*  */
    display: flex;
    flex-direction: column;
    align-items: center;
}
.tab.tab-search .search-form{/*  */
    width: 100%;
    font-size: 2rem;
    text-align: center;
}
.tab.tab-search .search-form label{/*  */
  width: 100%;
  position: relative;
}

.tab.tab-search .search-form input{/*  */
  font-family: 'Old Standard TT', serif; 
  font-size: 2rem;
  padding: 0.5rem;
  width: 90%;
}
.tab.tab-search .random-button{/*  */
  margin-top: 1rem;
  font-family: 'Old Standard TT', serif; 
  font-size: 2rem;
  padding: 0.5rem;
  color: #757575;
  transition: color 0.3s ease;
}
.tab.tab-search .random-button:hover{/*  */
  color: inherit;
}
.tab.tab-search .search-form .icon{/*  */
  position: absolute;
  color: #757575;
  right: 0.8rem;
  top: 0rem;
  /*right: 2.5rem;*/
}
.tab.tab-results ul{
    list-style-type: none;
    padding: 0;
}
/*  */
.tab.tab-results ul li {/*  */
    border: 1px solid #757575;
    padding: 0.5em 1em;
    margin-bottom: 1em;
    box-shadow: 1px 1px 5px #757575;
    transition: background-color 0.3s ease-in;
    cursor: pointer;
}
.tab.tab-results ul li:hover {/*  */
  background-color: #E0E0E0;
} 
.tab.tab-results ul li:hover a{/*  */
  font-weight: 600;
}
.tab.tab-results ul li a {
  text-decoration: none;
  font-family: 'Cabin', sans-serif;
  transition: font-weight 0.5s ease;
}

.tab.tab-article .tab-content .article-content{/*  */
  display: flex;
}
.tab.tab-article .tab-content .article-content p{
    padding-right: 3rem;
    text-align: justify;
 }
.tab.tab-article .tab-content .article-content img{
    max-width: 30%;
}
.tab.tab-article .tab-content 
  
class Tab extends React.Component {
    constructor(props) {
        super(props);
    }
    collapseAllTabs(){
        [...document.querySelectorAll(".tab-container .tab")].forEach(x=>{
            x.className = x.className.replace("collapsed","").concat(" collapsed");
          });
    }
   handleTabClick = (event)=> {
       this.collapseAllTabs();
       this.props.updateActive(this.props.title);
       /* let tab = event.target.parentNode;
       tab.className = tab.className.replace("collapsed",""); */
    }
    render(){
          let classNameTab = `tab tab-${this.props.title.toLowerCase()} ${this.props.active==this.props.title?"":"collapsed"}`;
          return(
              <div className={classNameTab}  >
                  <h2 className="tab-title" onClick={this.handleTabClick}>{this.props.title}</h2>
              {(()=>{
                      switch (this.props.title){
                          case "Search":
                              return  <div className="tab-content">
                                        <Search updateActive={this.props.updateActive} callback={this.props.callback}/>
                                        <Random updateActive={this.props.updateActive} loadArticle={this.props.loadArticle}/>
                                      </div>;
                              break;
                          case "Results":
                              return <div className="tab-content"><Results updateActive={this.props.updateActive} results={this.props.results} loadArticle={this.props.loadArticle}/></div>;
                              break;
                          case "Article":
                              return <div className="tab-content"><Article article={this.props.article}/></div>;
                              break;
                          default: break;
                      }
                    })()}
              </div>
          )
    }
}
Tab.propTypes = { title: React.PropTypes.oneOf(['Search', 'Results','Article']) }

class Random extends React.Component {
 getRandomArticle=()=>{/*  */
    const randomArticleAPIUrl = 'https://en.wikipedia.org/w/api.php?action=query&list=random&rnlimit=1&rnnamespace=0&origin=*&format=json';
    fetch(randomArticleAPIUrl)
      .then(response=>response.json())
      .then(json=>{ 
        this.props.loadArticle(json.query.random[0].id);
        this.props.updateActive('Article');
      });
 }
 render() {
        return (
          <button className="random-button" onClick={this.getRandomArticle}><i className="fa fa-random"></i> Random article </button>
        )/*  */
      }
}
class Search extends React.Component {
    constructor(props) {
      super(props);
      this.state = {text: ""};
    }
    handleChange(event){
      this.setState({text:event.target.value});
    }

    searchText=(event)=>{/*  */
      const apiUrl = `https://en.wikipedia.org/w/api.php?action=query&format=json&list=search&srsearch=${this.state.text.trim()}&origin=*`;
      console.log("I'm going to search for ", this.state.text);
      fetch(apiUrl)
        .then(res=>res.json())
        .then(json=>{ this.props.callback(json.query.search);})
        .catch(err=>console.dir(err) )
        .then(()=>{ this.props.updateActive('Results'); });
      
       event.preventDefault();
    }
    render() {
        return (
        <form id="search-form" className="search-form" onSubmit={this.searchText.bind(this)}>
           <label>  
             <input type="text" 
             value={this.state.text}
             onChange={this.handleChange.bind(this)}
             placeholder="Type and press enter to search into the Wikipedia..." 
             />
             <i className="fa fa-search icon" ></i></label>
        </form>
        );
    }
}
class Results extends React.Component {
    constructor(props) {
      super(props);
      this.state = {results: this.props.results};
    }
    componentWillReceiveProps(newProps) {
        console.log("Updating state from props change");
        this.setState({ results: newProps.results });
    }
    loadArticleOnClick=(event)=>{
      console.log(event);
      let el = event.target;
      while(el.tagName !== 'LI') // uppercase in HTML, lower in XML
      {
        el=el.parentNode;
       }
      this.props.loadArticle(el.dataset.pageid);
      this.props.updateActive('Article');
    }
    render() {
        /*let items = this.state.results.map(x=>{ console.log(x); return(<i class="fa fa-times"></i>)} );*/
        console.table(this.state.results);
        if (this.state.results){
            return (
            <ul>
                {
                this.state.results
                .map(x=>{ 
                return(
                    <li key={x.pageid} data-pageid={x.pageid} onClick={this.loadArticleOnClick}>
                    <a href="#" data-pageid={x.pageid}><i className="fa fa-file-text"></i> {x.title}</a>
                    <p>{x.snippet.replace(/&quot;/g, "\"").replace(/<span class="searchmatch">/g,"").replace(/<\/span>/g,"")} ... </p>
                    </li>
                )})}
            </ul>
            );
        }else{
            return (<p> No results </p>);
        }
       
}
}
class Article extends React.Component {
    constructor(props) {
      super(props);
      this.state = {article:{ pageId: "", url: ""}/*  */};
    }
    getArticleApiCall(pageId){/*  */
      return `https://en.wikipedia.org/w/api.php?action=query&prop=pageimages|extracts|info&pageids=${pageId}&inprop=url&exintro=&explaintext&pithumbsize=300&format=json&origin=*`
    }
    componentWillReceiveProps= (newProps)=> {
      console.log(newProps);
      if (newProps.article){
        console.log(`Updating state from props change [article: ${newProps.article}]`);
        fetch(this.getArticleApiCall(newProps.article))
        .then(res=>res.json())
        .then(json=>{
          console.log(json);
          this.setState({ article: 
                         { pageId: this.props.article,
                           title: json.query.pages[this.props.article].title,
                           extract: json.query.pages[this.props.article].extract,
                           image: json.query.pages[this.props.article].thumbnail? json.query.pages[this.props.article].thumbnail.source:"",
                           url: json.query.pages[this.props.article].fullurl
                         } 
                        } ); 
          /*  */
          } ).catch(err=>console.error(err));
      }
    }
    render() {
        return (
            <div>
            <h3>{this.state.article.title}</h3>
              <div className="article-content">
                <p>{this.state.article.extract}</p><img src={this.state.article.image}></img>
              </div>
              <blockquote cite={this.state.article.url}>
                See more in the Wikipedia article <a href={this.state.article.url} target="_blank">{this.state.article.title}</a>
              </blockquote>
            </div>
        ); 
    }
}
class App extends React.Component {
    constructor() {
        super();
        this.state = {
            results: [],  
            active: 'Search'
         };
    }
    callbackResults = (results)=>{
        this.setState({results: results});
      }
    updateActive = (tabTitle)=>{
        this.setState({active: tabTitle});
    }
    loadArticle = (articleId)=>{/*  */
      this.setState({articleId});
    }
    render() {
        return (
            <div>
                <h1><i className="fa fa-wikipedia-w"></i> Wikipedia viewer</h1>
                <div className="tab-container" >
                        <Tab title="Search"  active={this.state.active} updateActive={this.updateActive} callback={this.callbackResults} loadArticle={this.loadArticle}/>
                        <Tab title="Results" active={this.state.active} updateActive={this.updateActive} results={this.state.results} loadArticle={this.loadArticle} />
                        <Tab title="Article" active={this.state.active} updateActive={this.updateActive} article={this.state.articleId} />
                </div>
            </div>
        );
    }
}

ReactDOM.render(
    <App />
, document.getElementById('root'));
View Compiled

External CSS

  1. https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css

External JavaScript

  1. https://fb.me/react-0.14.3.js
  2. https://fb.me/react-dom-0.14.3.js