App.js (4380B)
1 import React from 'react'; 2 import { PieChart } from 'react-minimal-pie-chart'; 3 import Label from './Label.js'; 4 5 class App extends React.Component { 6 state = { 7 tags: [], 8 winner: -1, 9 index: -1, 10 theta: 0, 11 dtheta: 0, 12 }; 13 14 async spin() { 15 if (this.state.spinning) { 16 this.setState({ dtheta: 0 }); 17 return; 18 } 19 20 const url = document.location.hostname === 'localhost' ? 'http://localhost:5000/spin' : '/spin'; 21 const res = await fetch(url); 22 this.setState({ 23 tags: await res.json(), 24 spinning: true, 25 winner: -1, 26 theta: Math.random() * 360, 27 dtheta: 30 + Math.random(), 28 }); 29 30 let last = Date.now(); 31 const anim = () => { 32 const dt = last - Date.now(); 33 this.update(dt); 34 35 if (this.state.dtheta > 0.01) { 36 last = Date.now(); 37 requestAnimationFrame(anim); 38 } else { 39 this.setState({ 40 spinning: false, 41 winner: this.state.index 42 }); 43 } 44 } 45 requestAnimationFrame(anim); 46 } 47 48 update(dt) { 49 const index = Math.floor(this.state.tags.length * (360-((this.state.theta+89)%360)) / 360); 50 51 if (index !== this.state.index) { 52 new Audio('/click.mp3').play(); 53 } 54 55 this.setState({ 56 index, 57 theta: this.state.theta + this.state.dtheta, 58 dtheta: this.state.dtheta * 0.995, 59 }) 60 } 61 62 winner() { 63 if (this.state.winner < 0) { 64 return ( 65 <div> 66 <strong> 67 { this.state.spinning 68 ? 'Click the wheel to stop spinning!' 69 : 'Click the wheel to spin!' 70 } 71 </strong><br /> 72 <img className="wop" alt="Time to spin the wheel of porn" src="/wheelofporn.gif" /> 73 </div> 74 ); 75 } 76 77 const winner = this.state.tags[this.state.winner]; 78 return ( 79 <div className="winner"> 80 <h1>Your tag is: {winner.name}</h1> 81 <ul> 82 { winner.sites.map(site => ( 83 <li key={site.baseUrl}> 84 <a href={site.url}> 85 <img alt="" src={site.icon} /> 86 <strong>{site.hostname}</strong> 87 </a> 88 </li> 89 )) } 90 </ul> 91 </div> 92 ) 93 } 94 95 render() { 96 const { tags } = this.state; 97 return ( 98 <div className="app"> 99 <div className="spinner-container"> 100 <div 101 onClick={ () => this.spin() } 102 className="spinner" 103 style={{ 104 transform: `translate(-50%) rotate(${this.state.theta}deg)`, 105 }} 106 > 107 <PieChart 108 className="wheel" 109 totalValue={tags.length} 110 paddingAngle={1} 111 labelPosition="95" 112 label={ 113 props => ( 114 <Label key={tags[props.dataIndex].name} {...props}> 115 {tags[props.dataIndex].name.toUpperCase()} 116 </Label> 117 ) 118 } 119 data={ 120 tags.map((tag, i) => ({ 121 title: `${tag.name}: ${tag.sites.length} sites`, 122 value: 1, 123 color: `hsl(${360 * i*3/tags.length}, 100%, ${i === this.state.index ? 70 : 40}%)`, 124 })) 125 } 126 /> 127 </div> 128 <div className="arrow"></div> 129 </div> 130 { this.winner() } 131 </div> 132 ); 133 } 134 } 135 136 export default App;