// Built with the Navigation router // https://grahammendick.github.io/navigation/ const { StateNavigator } = Navigation; const { NavigationLink, NavigationBackLink } = NavigationReact; const { NavigationMotion, MobileHistoryManager } = NavigationReactMobile; const Banner = ({title, stateNavigator}) => ( <div className="banner"> <NavigationBackLink distance={1} stateNavigator={stateNavigator}> <svg className="back" viewBox="0 0 24 24"> <g> <path d="M20 11H7.414l4.293-4.293a1 1 0 0 0-1.414-1.414l-6 6a1 1 0 0 0 0 1.414l6 6a.996.996 0 0 0 1.414 0 1 1 0 0 0 0-1.414L7.414 13H20a1 1 0 1 0 0-2z"></path> </g> </svg> </NavigationBackLink> <h1>{title}</h1> </div> ); const Home = ({tweets, stateNavigator}) => ( <div> <div className="tabs"> <h1>Home</h1> <svg className="home" viewBox="0 0 24 24"> <g> <path d="M22.58 7.35L12.475 1.897a1 1 0 0 0-.95 0L1.425 7.35A1.002 1.002 0 0 0 1.9 9.231c.16 0 .324-.038.475-.12l.734-.396 1.59 11.25c.216 1.214 1.31 2.062 2.66 2.062h9.282c1.35 0 2.444-.848 2.662-2.088l1.588-11.225.737.398a1 1 0 0 0 .95-1.759zM12 15.435a3.25 3.25 0 1 1 0-6.5 3.25 3.25 0 0 1 0 6.5z"></path> </g> </svg> </div> <Tweets tweets={tweets} stateNavigator={stateNavigator} /> </div> ); const Timeline = ({timeline: {id, name, username, logo, bio, followers, following, tweets}, stateNavigator}) => ( <div> <Banner title={name} stateNavigator={stateNavigator} /> <div className="profile"> <div className="pic" /> <img src={logo} alt={name}/> <div className="details"> <div className="name">{name}</div> <div className="username">{username}</div> <div className="bio">{bio}</div> </div> <div className="interactions"> <div className="count">{following.toLocaleString()}</div> <div className="interaction">Following</div> <div className="count">{followers.toLocaleString()}</div> <div className="interaction">Followers</div> </div> </div> <Tweets tweets={tweets} onTimeline={(e, accountId) => { if (accountId === id) { e.preventDefault(); e.target.closest('.scene').scrollTop = 0; } return accountId !== id; }} stateNavigator={stateNavigator} /> </div> ); const Tweet = ({tweet: {account: {id: accountId, name, username, logo}, text, time, retweets, likes, replies}, stateNavigator}) => ( <div> <Banner title="Tweet" stateNavigator={stateNavigator} /> <div className="tweet"> <div className="heading"> <NavigationLink className="logo" stateKey="timeline" navigationData={{id: accountId}} stateNavigator={stateNavigator}> <img src={logo} alt={name}/> </NavigationLink> <div className="details"> <div className="name">{name}</div> <div className="username">{username}</div> </div> </div> <div className="text">{text}</div> <div className="time">{time}</div> <div className="interactions"> <div className="count">{retweets}</div> <div className="interaction">Retweets</div> <div className="count">{likes}</div> <div className="interaction">Likes</div> </div> </div> <Tweets tweets={replies} stateNavigator={stateNavigator} /> </div> ); const Tweets = ({tweets, onTimeline, stateNavigator}) => ( <ul> {tweets.map(({account: {id: accountId, name, logo}, id, text}) => ( <li key={id} className="tweet"> <NavigationLink className="logo" stateKey="timeline" navigationData={{id: accountId}} navigating={e => !onTimeline || onTimeline(e, accountId)} stateNavigator={stateNavigator}> <img src={logo} alt={name}/> </NavigationLink> <NavigationLink className="details" stateKey="tweet" navigationData={{id}} stateNavigator={stateNavigator}> <div className="name">{name}</div> <div>{text}</div> </NavigationLink> </li> ))} </ul> ); const Twitter = ({stateNavigator}) => ( <NavigationMotion unmountedStyle={{translate: 100, scale: 1, opacity: 1}} mountedStyle={{translate: 0, scale: 1, opacity: 1}} crumbStyle={{translate: 5, scale: 0.9, opacity: 0}} stateNavigator={stateNavigator}> {({translate, scale, opacity}, scene, key) => ( <div key={key} className="scene" style={{ transform: `translate(${translate}%, 0) scale(${scale}, ${scale})`, opacity }}> {scene} </div> )} </NavigationMotion> ); const stateNavigator = new StateNavigator([ {key: 'home', route: ''}, {key: 'tweet', trackCrumbTrail: true}, {key: 'timeline', trackCrumbTrail: true} ], new MobileHistoryManager(url => { var {state, data} = stateNavigator.parseLink(url); return stateNavigator.fluent() .navigate('home') .navigate(state.key, data).url; })); const {home, tweet, timeline} = stateNavigator.states; home.renderScene = () => <Home tweets={getHome()} stateNavigator={stateNavigator}/>; tweet.renderScene = ({id}) => <Tweet tweet={getTweet(id)} stateNavigator={stateNavigator}/>; timeline.renderScene = ({id}) => <Timeline timeline={getTimeline(id)} stateNavigator={stateNavigator}/>; ReactDOM.render( <Twitter stateNavigator={stateNavigator} />, document.getElementById('app') ) const accounts = { 1: { name: 'Preethi Kasireddy', username: '@iam_preethi', logo: 'https://navigation4asp.files.wordpress.com/2018/01/iam_preethi.jpg', bio: 'Software Engineer @coinbase. Previously @a16z & @GoldmanSachs. Besides doing nerdy things, I love running & reading. I believe in the magic of thinking big :)', following: 763, followers: 6722, tweets: [1, 2, 5, 3, 4] }, 2: { name: 'Sebastian Markbåge', username: '@sebmarkbage', logo: 'https://navigation4asp.files.wordpress.com/2018/01/sebmarkbage.jpg', bio: 'React JS · TC39 · The Facebook · Tweets are personal', following: 354, followers: 14319, tweets: [5, 6, 9, 7, 8] }, 3: { name: 'Dan Abramov', username: '@dan_abramov', logo: 'https://navigation4asp.files.wordpress.com/2018/01/dan_abramov.jpg', bio: 'Co-authored Redux, Create React App, React Hot Loader, React DnD. Helping improve @reactjs. Personal opinions. #juniordevforlife', following: 1576, followers: 52822, tweets: [9, 10, 1, 11, 12] } }; const tweets = { 1: { account: 1, text: 'When you hear a dogmatic opinion about some code, best practice or tool.. question it. Most things in programming are not so black & white.', time: '6:49 PM - 30 Oct 2016', retweets: 120, likes: 207, replies: [4, 8, 5] }, 2: { account: 1, text: 'My favorite thing about programming is the never-ending, "mind-blown", euphoric moments you have from learning or realizing something new', time: '11:14 PM - 15 Oct 2016', retweets: 95, likes: 259, replies: [9, 3] }, 3: { account: 1, text: 'One of the hardest things as a programmer is knowing which rabbit holes are worth descending into', time: '5:21 AM - 7 Oct 2016', retweets: 521, likes: 945, replies: [6] }, 4: { account: 1, text: 'If you\'re worried about what other people will think of you for doing X or Y, dont be. Most people are too busy thinking about themselves', time: '7:15 PM - 29 Jun 2016', retweets: 30, likes: 60, replies: [10, 7, 11, 2] }, 5: { account: 2, text: 'My main goal with React isn\'t for the library/code to "win" but for the lessons learned not to go forgotten. That\'s surprisingly difficult.', time: '6:45 PM - 20 Oct 2016', retweets: 52, likes: 192, replies: [1, 12, 8] }, 6: { account: 2, text: 'Each pattern by itself can\'t be said to be "best practice" without the context of other patterns it needs to work with.', time: '8:23 PM - 20 Sep 2016', retweets: 10, likes: 24, replies: [4, 3] }, 7: { account: 2, text: 'Server-side only doesn\'t work because high latency/fragile updates. Downloading JS on-demand doesn\'t work because slow to download+compile.', time: '5:37 AM - 16 Sep 2016', retweets: 2, likes: 13, replies: [6] }, 8: { account: 2, text: 'Don\'t confuse identifying a problem with solving a problem. There\'s a very long tail that follows.', time: '8:15 AM - 30 Aug 2016', retweets: 15, likes: 40, replies: [10, 9, 7, 2] }, 9: { account: 3, text: 'Code is not just a static snapshot of the requirements and tradeoffs, but a living collaborative document pulled into many directions.', time: '5:29 PM - 31 Oct 2016', retweets: 27, likes: 63, replies: [7] }, 10: { account: 3, text: 'Don\'t write "flexible" modules. No matter how you plan, you\'ll miss some future requirements. Write modules that are easy to delete.', time: '5:15 PM - 31 Oct 2016', retweets: 339, likes: 534, replies: [2, 1, 6, 8] }, 11: { account: 3, text: 'I like reaching that point when tests no longer express my wishes but help me discover and understand the system.', time: '4:06 PM - 28 Oct 2016', retweets: 9, likes: 70, replies: [4, 10] }, 12: { account: 3, text: 'I feel very anxious when I approach new code so I add logging everywhere. This helps so much.', time: '10:37 PM - 13 Oct 2016', retweets: 16, likes: 112, replies: [9, 5] }, }; const fetchTweet = id => ({ id, ...tweets[id], account: { id: tweets[id].account, ...accounts[tweets[id].account] } }); const getHome = () => { const homeTweets = [1, 5, 9, 2, 6, 10]; return homeTweets.map(id => fetchTweet(id)); }; const getTweet = id => { const tweet = fetchTweet(id); tweet.replies = tweet.replies.map(replyId => fetchTweet(replyId)); return tweet; }; const getTimeline = id => { const timeline = { ...accounts[id], id }; timeline.tweets = timeline.tweets.map(tweetId => fetchTweet(tweetId)); return timeline; }; stateNavigator.start();

!