├── .gitignore ├── README.md ├── server-files.rar ├── ui ├── index.html ├── styles │ └── app.scss └── app │ ├── bridge.js │ └── app.js ├── index.js ├── webpack.config.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /package-lock.json 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rage-mp-react-ui 2 | Example repo to explain how use react in rage mp servers 3 | -------------------------------------------------------------------------------- /server-files.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mispon/rage-mp-react-ui/HEAD/server-files.rar -------------------------------------------------------------------------------- /ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | let browser 2 | 3 | mp.events.add('guiReady', () => { 4 | browser = mp.browsers.new('package://ui/index.html') 5 | }) 6 | 7 | // Handle event from server and send data to react app 8 | mp.events.add('onMessageFromServer', (value) => { 9 | browser.execute(`trigger('onMessage', '${value}')`) 10 | }) 11 | 12 | // Handle event from react app 13 | mp.events.add('showUrl', (url) => { 14 | mp.gui.chat.push(url) 15 | }) 16 | 17 | // F12 - trigger cursor 18 | mp.keys.bind(0x7B, true, () => { 19 | let state = !mp.gui.cursor.visible 20 | mp.gui.cursor.show(state, state) 21 | }) -------------------------------------------------------------------------------- /ui/styles/app.scss: -------------------------------------------------------------------------------- 1 | .app { 2 | h1 { 3 | text-align: center; 4 | font-weight: bold; 5 | padding-top: 2vh; 6 | } 7 | .message { 8 | text-align: center; 9 | font-size: 2vw; 10 | padding-top: 2vh; 11 | } 12 | .current-time { 13 | display: block; 14 | position: absolute; 15 | right: 1vw; 16 | bottom: 0; 17 | } 18 | .send-button { 19 | display: block; 20 | width: 100px; 21 | height: 50px; 22 | margin: 15% auto; 23 | outline: none; 24 | } 25 | position: relative; 26 | width: 30%; 27 | height: 40vh; 28 | margin: 20vh auto; 29 | border-radius: 10px; 30 | box-shadow: 1px 1px 2px black; 31 | background-color: black; 32 | color: white; 33 | } -------------------------------------------------------------------------------- /ui/app/bridge.js: -------------------------------------------------------------------------------- 1 | // Global variable for subscribe on events from react components 2 | var EventManager = { 3 | events: {}, 4 | 5 | addHandler: function(eventName, handler) { 6 | if (eventName in this.events) { 7 | this.events[eventName].push(handler); 8 | } 9 | else { 10 | this.events[eventName] = [handler]; 11 | } 12 | }, 13 | 14 | removeHandler: function(eventName, handler) { 15 | if (eventName in this.events) { 16 | var index = this.events[eventName].indexOf(handler); 17 | this.events[eventName].splice(index, 1); 18 | } 19 | } 20 | } 21 | 22 | // Handle events from client 23 | function trigger(eventName, args) { 24 | var handlers = EventManager.events[eventName]; 25 | handlers.forEach(handler => handler(JSON.parse(args))); 26 | } 27 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const path = require('path') 3 | 4 | let NODE_ENV = 'production' 5 | if (process.env.NODE_ENV) { 6 | NODE_ENV = process.env.NODE_ENV.replace(/^\s+|\s+$/g, "") 7 | } 8 | 9 | module.exports = { 10 | entry: { 11 | index: './index.js', 12 | app: './ui/app/app.js' 13 | }, 14 | output: { 15 | path: path.resolve(__dirname, 'build'), 16 | filename: '[name].js' 17 | }, 18 | watch: NODE_ENV == 'development', 19 | module: { 20 | rules: [{ 21 | test: /\.js$/, 22 | exclude: [/node_modules/], 23 | loader: 'babel-loader', 24 | query: { 25 | presets: ['react', 'es2015'] 26 | } 27 | }, 28 | { 29 | test: /\.scss$/, 30 | use: ["style-loader", "css-loader", "sass-loader"] 31 | } 32 | ] 33 | }, 34 | resolve: { 35 | extensions: ['.js', '.json'] 36 | }, 37 | optimization: { 38 | minimize: true 39 | }, 40 | mode: NODE_ENV, 41 | plugins: [ 42 | new webpack.EnvironmentPlugin('NODE_ENV') 43 | ] 44 | }; 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rage-mp-react-ui", 3 | "version": "1.0.0", 4 | "description": "Example repo to explain how use react in rage mp servers", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npm run dev", 8 | "dev": "set NODE_ENV=development && webpack", 9 | "prod": "set NODE_ENV=production && webpack" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/Mispon/rage-mp-react-ui.git" 14 | }, 15 | "keywords": [ 16 | "rage-mp", 17 | "react", 18 | "rage", 19 | "mispon", 20 | "gta5", 21 | "gtav" 22 | ], 23 | "author": "Mispon", 24 | "license": "ISC", 25 | "bugs": { 26 | "url": "https://github.com/Mispon/rage-mp-react-ui/issues" 27 | }, 28 | "homepage": "https://github.com/Mispon/rage-mp-react-ui#readme", 29 | "devDependencies": { 30 | "babel-core": "^6.26.3", 31 | "babel-loader": "^7.1.5", 32 | "babel-preset-es2015": "^6.24.1", 33 | "babel-preset-react": "^6.24.1", 34 | "css-loader": "^1.0.0", 35 | "node-sass": "^4.9.3", 36 | "sass-loader": "^7.1.0", 37 | "style-loader": "^0.23.0", 38 | "webpack": "^4.20.2", 39 | "webpack-cli": "^3.1.2" 40 | }, 41 | "dependencies": { 42 | "react": "^16.5.2", 43 | "react-dom": "^16.5.2" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ui/app/app.js: -------------------------------------------------------------------------------- 1 | import '../styles/app.scss' 2 | 3 | import React from 'react' 4 | import ReactDOM from 'react-dom' 5 | 6 | class App extends React.Component { 7 | constructor(props) { 8 | super(props) 9 | this.state = { 10 | time: new Date(), 11 | message: 'default message' 12 | } 13 | } 14 | 15 | componentDidMount() { 16 | EventManager.addHandler('onMessage', this.onMessage.bind(this)) 17 | this.timerId = setInterval(() => { 18 | this.setState({time: new Date()}) 19 | }, 1000) 20 | } 21 | 22 | componentWillUnmount() { 23 | clearInterval(this.timerId) 24 | EventManager.removeHandler('onMessage', this.onMessage) 25 | } 26 | 27 | onMessage(value) { 28 | this.setState({message: value}) 29 | } 30 | 31 | // send current url to client 32 | click() { 33 | let currentUrl = window.location.pathname 34 | mp.trigger('showUrl', currentUrl) 35 | } 36 | 37 | render() { 38 | return( 39 |
40 |

Make UI on React!

41 |

{this.state.time.toLocaleTimeString()}

42 |

{this.state.message}

43 | 44 |
45 | ) 46 | } 47 | } 48 | 49 | ReactDOM.render(, document.getElementById('root')) --------------------------------------------------------------------------------