├── README.md ├── client.lua ├── config.lua ├── fxmanifest.lua └── html ├── index.html ├── script.js └── style.css /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

Hi there, Im didAX19

4 |

5 | 6 | # QB Input Redesign 7 | - New modern design with redesigned inputs. 8 | - You can choose between dark or light modes in the configuration. 9 | 10 | # Preview 11 |
12 | 13 | # Support ? 14 | Welcome to our Discord server. 15 | -------------------------------------------------------------------------------- /client.lua: -------------------------------------------------------------------------------- 1 | local properties = nil 2 | 3 | RegisterNUICallback("buttonSubmit", function(data, cb) 4 | SetNuiFocus(false) 5 | properties:resolve(data.data) 6 | properties = nil 7 | cb("ok") 8 | end) 9 | 10 | RegisterNUICallback("closeMenu", function(_, cb) 11 | SetNuiFocus(false) 12 | properties:resolve(nil) 13 | properties = nil 14 | cb("ok") 15 | end) 16 | 17 | local function ShowInput(data) 18 | Wait(150) 19 | if not data then return end 20 | if properties then return end 21 | properties = promise.new() 22 | 23 | SetNuiFocus(true, true) 24 | SendNUIMessage({ 25 | action = "OPEN_MENU", 26 | data = data, 27 | darkMode = Config.darkMode 28 | }) 29 | 30 | return Citizen.Await(properties) 31 | end 32 | 33 | exports("ShowInput", ShowInput) -------------------------------------------------------------------------------- /config.lua: -------------------------------------------------------------------------------- 1 | Config = {} 2 | 3 | Config.darkMode = true -------------------------------------------------------------------------------- /fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version 'cerulean' 2 | game 'gta5' 3 | 4 | description 'QB-Input Redesigned by didax19' 5 | version '0.0.1' 6 | 7 | client_scripts { 8 | 'client.lua', 9 | 'config.lua', 10 | } 11 | 12 | ui_page 'html/index.html' 13 | 14 | files { 15 | 'html/index.html', 16 | 'html/style.css', 17 | 'html/script.js' 18 | } 19 | 20 | lua54 'yes' 21 | -------------------------------------------------------------------------------- /html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | QB INPUT Redesigned by didax19 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | 16 | -------------------------------------------------------------------------------- /html/script.js: -------------------------------------------------------------------------------- 1 | let formInputs = {}; 2 | let darkModeEnabled = true; // Set this variable to true for dark mode, false for default colors 3 | 4 | $(window).resize(function () { 5 | updateMainWrapperHeight(); 6 | }); 7 | 8 | const updateMainWrapperHeight = () => { 9 | const wrapper = $(".main-wrapper"); 10 | const windowHeight = $(window).height(); 11 | const wrapperTopOffset = wrapper.offset().top; 12 | const maxHeight = windowHeight - wrapperTopOffset; 13 | wrapper.css("max-height", maxHeight + "px"); 14 | }; 15 | 16 | const OpenMenu = (data, darkModeEnabled) => { 17 | if (data == null || data == "") { 18 | console.log("No data detected"); 19 | return null; 20 | } 21 | 22 | let showContainer = () => { 23 | $(".background").fadeIn(); 24 | $(".main-wrapper").addClass(darkModeEnabled ? "dark-mode" : ""); 25 | $(".main-wrapper").fadeIn(); 26 | }; 27 | 28 | showContainer(); 29 | updateMainWrapperHeight(); 30 | 31 | let form = [ 32 | "
", 33 | `
${data.header != null ? data.header : "Form Title"}
`, 34 | `
`, 35 | ]; 36 | 37 | data.inputs.forEach((item, index) => { 38 | switch (item.type) { 39 | case "text": 40 | form.push(renderTextInput(item)); 41 | break; 42 | case "password": 43 | form.push(renderPasswordInput(item)); 44 | break; 45 | case "number": 46 | form.push(renderNumberInput(item)); 47 | break; 48 | case "radio": 49 | form.push(renderRadioInput(item)); 50 | break; 51 | case "select": 52 | form.push(renderSelectInput(item)); 53 | break; 54 | case "checkbox": 55 | form.push(renderCheckboxInput(item)); 56 | break; 57 | default: 58 | form.push(`
${item.text}
`); 59 | } 60 | if (index !== data.inputs.length - 1) { 61 | form.push(`
`); 62 | } 63 | }); 64 | form.push( 65 | `
` 66 | ); 67 | 68 | form.push("
"); 69 | 70 | $(".main-wrapper").html(form.join(" ")); 71 | 72 | $("#qb-input-form").on("change", function (event) { 73 | if( $(event.target).attr("type") == 'checkbox' ) { 74 | const value = $(event.target).is(":checked") ? "true" : "false"; 75 | formInputs[$(event.target).attr("value")] = value; 76 | }else{ 77 | formInputs[$(event.target).attr("name")] = $(event.target).val(); 78 | } 79 | }); 80 | 81 | $("#qb-input-form").on("submit", async function (event) { 82 | if (event != null) { 83 | event.preventDefault(); 84 | } 85 | await $.post( 86 | `https://${GetParentResourceName()}/buttonSubmit`, 87 | JSON.stringify({ data: formInputs }) 88 | ); 89 | CloseMenu(); 90 | }); 91 | }; 92 | 93 | const renderTextInput = (item) => { 94 | const { text, name } = item; 95 | formInputs[name] = item.default ? item.default : ""; 96 | const isRequired = item.isRequired == "true" || item.isRequired ? "required" : ""; 97 | const defaultValue = item.default ? `value="${item.default}"` : "" 98 | 99 | return ` `; 100 | }; 101 | const renderPasswordInput = (item) => { 102 | const { text, name } = item; 103 | formInputs[name] = item.default ? item.default : ""; 104 | const isRequired = item.isRequired == "true" || item.isRequired ? "required" : ""; 105 | const defaultValue = item.default ? `value="${item.default}"` : "" 106 | 107 | return ` `; 108 | }; 109 | const renderNumberInput = (item) => { 110 | try { 111 | const { text, name } = item; 112 | formInputs[name] = item.default ? item.default : ""; 113 | const isRequired = item.isRequired == "true" || item.isRequired ? "required" : ""; 114 | const defaultValue = item.default ? `value="${item.default}"` : ""; 115 | 116 | return ``; 117 | } catch (err) { 118 | console.log(err); 119 | return ""; 120 | } 121 | }; 122 | 123 | const renderRadioInput = (item) => { 124 | const { options, name, text } = item; 125 | formInputs[name] = options[0].value; 126 | 127 | let div = `
${text}
`; 128 | div += '
'; 129 | options.forEach((option, index) => { 130 | div += ``; 132 | }); 133 | 134 | div += "
"; 135 | div += "
"; 136 | return div; 137 | }; 138 | 139 | const renderCheckboxInput = (item) => { 140 | const { options, name, text } = item; 141 | 142 | 143 | let div = `
${text}
`; 144 | div += '
'; 145 | 146 | options.forEach((option, index) => { 147 | div += ``; 151 | formInputs[option.value] = option.checked ? 'true' : 'false'; 152 | }); 153 | 154 | div += "
"; 155 | div += "
"; 156 | return div; 157 | }; 158 | 159 | const renderSelectInput = (item) => { 160 | const { options, name, text } = item; 161 | let div = `
${text}
`; 162 | 163 | div += `"; 172 | return div; 173 | }; 174 | 175 | const CloseMenu = () => { 176 | $(`.main-wrapper`).fadeOut(0); 177 | $("#qb-input-form").remove(); 178 | formInputs = {}; 179 | }; 180 | 181 | const CancelMenu = () => { 182 | $.post(`https://${GetParentResourceName()}/closeMenu`); 183 | return CloseMenu(); 184 | }; 185 | 186 | window.addEventListener("message", (event) => { 187 | const data = event.data; 188 | const info = data.data; 189 | const action = data.action; 190 | const darkModeEnabled = data.darkMode; 191 | switch (action) { 192 | case "OPEN_MENU": 193 | return OpenMenu(info, darkModeEnabled); 194 | case "CLOSE_MENU": 195 | return CloseMenu(); 196 | default: 197 | return; 198 | } 199 | }); 200 | 201 | document.onkeyup = function (event) { 202 | const charCode = event.key; 203 | if (charCode == "Escape") { 204 | CancelMenu(); 205 | } else if (charCode == "Enter") { 206 | SubmitData(); 207 | } 208 | }; 209 | 210 | $(document).click(function (event) { 211 | var $target = $(event.target); 212 | if ( 213 | !$target.closest(".main-wrapper").length && 214 | $(".main-wrapper").is(":visible") 215 | ) { 216 | CancelMenu(); 217 | } 218 | }); -------------------------------------------------------------------------------- /html/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;500&display=swap"); 2 | 3 | :root { 4 | --primary-color: #f2f2f2; 5 | --secondary-color: #190A28; 6 | --accent-color: #D095FA; 7 | --input-hover: #D095FA; 8 | --text-color: #190A28; 9 | --select-bg: #A86DF9; 10 | --select-hover: #D095FA; 11 | --scrollbar-thumb: #D095FA; 12 | --scrollbar-color: #f7f7f7; 13 | } 14 | 15 | .dark-mode { 16 | --primary-color: #190A28; 17 | --secondary-color: #f2f2f2; 18 | --accent-color: #491085; 19 | --input-hover: #240842; 20 | --text-color: #ffffff; 21 | --select-bg: #A86DF9; 22 | --select-hover: #491085; 23 | --scrollbar-thumb: #6E19C8; 24 | --scrollbar-color: #240842; 25 | } 26 | 27 | * { 28 | padding: 0; 29 | margin: 0; 30 | font-family: "Poppins", sans-serif; 31 | font-weight: 300; 32 | } 33 | 34 | html, 35 | body { 36 | background: transparent; 37 | } 38 | 39 | .root-wrapper { 40 | width: 30vw; 41 | height: auto; 42 | top: 31.2%; 43 | left: 62.5%; 44 | transform: translate(-50%, -50%); 45 | position: absolute; 46 | background: transparent; 47 | opacity: .9; 48 | } 49 | 50 | .main-wrapper { 51 | margin: auto; 52 | margin-top: 64.2%; 53 | width: 300px; 54 | padding-bottom: 10px; 55 | border-radius: 9px; 56 | height: auto; 57 | position: relative; 58 | display: flex; 59 | flex-direction: column; 60 | } 61 | 62 | ::-webkit-scrollbar { 63 | width: 6px; 64 | } 65 | 66 | ::-webkit-scrollbar-track { 67 | background: var(--scrollbar-color); 68 | border-radius: 3px; 69 | } 70 | 71 | ::-webkit-scrollbar-thumb { 72 | background: var(--scrollbar-thumb); 73 | border-radius: 3px; 74 | } 75 | 76 | .heading { 77 | display: flex; 78 | justify-content: center; 79 | margin-bottom: 1.5vh; 80 | color: var(--secondary-color); 81 | background: linear-gradient(140deg, #D095FA 0%, #6E19C8 100%)!important; 82 | border-radius: 10px; 83 | font-size: 18px; 84 | font-weight: 500; 85 | padding: 10.5px; 86 | } 87 | 88 | .heading h1 { 89 | position: relative; 90 | } 91 | 92 | .inputs { 93 | max-height: 60vh; 94 | background: var(--primary-color); 95 | border-radius: 10px; 96 | overflow: auto; 97 | } 98 | 99 | input:last-of-type { 100 | border-radius: 0px 0px 10px 10px; 101 | } 102 | 103 | input:first-of-type { 104 | border-radius: 10px 10px 0px 0px; 105 | } 106 | 107 | input:only-of-type { 108 | border-radius: 10px 10px 10px 10px; 109 | } 110 | 111 | .divider { 112 | width: 100%; 113 | height: 1px; 114 | background-color: var(--accent-color); 115 | } 116 | 117 | .form { 118 | width: 100%; 119 | height: auto; 120 | min-height: 10%; 121 | max-height: 70%; 122 | margin: auto; 123 | display: flex; 124 | flex-direction: column; 125 | } 126 | 127 | .form label { 128 | margin-top: 24px; 129 | } 130 | 131 | .form-control[type="number"] { 132 | appearance: none; 133 | -webkit-appearance: none; 134 | } 135 | 136 | .form-control[type="text"], 137 | .form-control[type="number"], 138 | .form-control[type="password"] { 139 | border: none; 140 | font-size: 14px; 141 | padding: 5px 0px; 142 | height: 50px; 143 | text-align: center; 144 | background: transparent; 145 | background-color: transparent; 146 | width: 100%; 147 | color: var(--text-color); 148 | transition: background-color .25s ease-in; 149 | } 150 | 151 | .form-control[type="text"]:focus, 152 | .form-control[type="number"]:focus, 153 | .form-control[type="password"]:focus { 154 | outline: none; 155 | background-color: var(--input-hover); 156 | } 157 | 158 | 159 | input::-webkit-outer-spin-button, 160 | input::-webkit-inner-spin-button { 161 | -webkit-appearance: none; 162 | background: var(--select-bg) url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAKUlEQVQYlWNgwAT/sYhhKPiPT+F/LJgEsHv37v+EMGkmkuImoh2NoQAANlcun/q4OoYAAAAASUVORK5CYII=) no-repeat center center; 163 | width: 1.2em; 164 | height: 1.5rem; 165 | opacity: .5; 166 | border-radius: 5px; 167 | transition: opacity .25s ease-in; 168 | } 169 | 170 | input::-webkit-inner-spin-button:hover, 171 | input::-webkit-inner-spin-button:active{ 172 | opacity: .8; 173 | } 174 | 175 | 176 | input[type=radio]{ 177 | appearance: none; 178 | cursor: pointer; 179 | background-color: var(--input-hover); 180 | margin: 0; 181 | font: inherit; 182 | width: 1.15em; 183 | height: 1.15em; 184 | border: 0.15em solid var(--select-hover); 185 | border-radius: 50%; 186 | translate: -0.1em 0.15em; 187 | transition: all .35s ease; 188 | margin-left: .4vh; 189 | } 190 | 191 | input[type="radio"]:hover { 192 | transform: scale(1.1); 193 | background-color: var(--select-hover); 194 | } 195 | 196 | input[type="radio"]:checked { 197 | transform: scale(1); 198 | background-color: var(--select-bg); 199 | } 200 | 201 | 202 | input[type=checkbox] { 203 | visibility: hidden; 204 | } 205 | 206 | .checkmark { 207 | position: relative; 208 | top: 0; 209 | left: 0; 210 | height: 19px; 211 | width: 19px; 212 | background-color: var(--select-hover); 213 | border-radius: 5px; 214 | transition: all .2s ease-in; 215 | } 216 | 217 | .checklabel { 218 | display: flex; 219 | position: relative; 220 | cursor: pointer; 221 | } 222 | 223 | .checklabel:hover input~.checkmark { 224 | background-color: var(--select-bg); 225 | } 226 | 227 | .checklabel input:checked~.checkmark { 228 | background-color: var(--select-bg); 229 | } 230 | 231 | .checkmark:after { 232 | content: ""; 233 | position: relative; 234 | display: block; 235 | opacity: 0; 236 | } 237 | 238 | .checklabel input:checked~.checkmark:after { 239 | opacity: 1; 240 | } 241 | 242 | .checklabel .checkmark:after { 243 | left: 6px; 244 | top: 2px; 245 | width: 4px; 246 | height: 8px; 247 | border: solid white; 248 | border-width: 0 3px 3px 0; 249 | -webkit-transform: rotate(45deg); 250 | -ms-transform: rotate(45deg); 251 | transform: rotate(45deg); 252 | transition: all .25s ease-in; 253 | } 254 | 255 | 256 | .form-input-group { 257 | padding-top: 5px; 258 | padding-bottom: 10px; 259 | padding: 5px; 260 | } 261 | 262 | .input-group { 263 | display: flex; 264 | flex-flow: row wrap; 265 | justify-content: space-evenly; 266 | } 267 | 268 | .input-group-chk { 269 | display: flex; 270 | flex-flow: column wrap; 271 | align-content: center; 272 | justify-content: center; 273 | } 274 | 275 | .input-group label { 276 | color: var(--text-color); 277 | } 278 | 279 | .input-group label:checked { 280 | color: var(--accent-color); 281 | } 282 | 283 | .form-group-title { 284 | font-size: 18px; 285 | font-weight: 400; 286 | width: 100%; 287 | text-align: center; 288 | color: var(--text-color); 289 | } 290 | 291 | .select-title { 292 | margin: 5px 0px; 293 | padding: 5px; 294 | text-align: center; 295 | font-size: 18px; 296 | font-weight: 400; 297 | color: var(--text-color); 298 | } 299 | 300 | .form-select { 301 | cursor: pointer; 302 | width: 100%; 303 | font-size: 14px; 304 | font-weight: 500; 305 | background: transparent; 306 | margin-top: 2.5px; 307 | margin-bottom: 10px; 308 | padding: 5px; 309 | border: none; 310 | outline: none; 311 | height: 50px; 312 | color: var(--text-color); 313 | transition: background-color .25s ease-in; 314 | } 315 | 316 | .form-select:hover { 317 | background-color: var(--input-hover); 318 | } 319 | 320 | .form-select > option { 321 | outline: none; 322 | border: none; 323 | cursor: pointer; 324 | background-color: var(--select-bg); 325 | color: var(--secondary-color); 326 | } 327 | 328 | .form-select > option:focus, 329 | .form-select > option:hover { 330 | background-color: var(--select-hover); 331 | } 332 | 333 | 334 | .form-select:active, 335 | .form-select:focus { 336 | width: 100%; 337 | margin-top: 2.5px; 338 | margin-bottom: 10px; 339 | padding: 5px; 340 | border: none; 341 | } 342 | 343 | .form-select:focus-visible { 344 | outline: none; 345 | } 346 | 347 | .input-group-chk label { 348 | color: var(--text-color); 349 | } 350 | 351 | ::placeholder { 352 | opacity: 65%; 353 | font-size: 14px; 354 | font-weight: 500; 355 | color: var(--text-color); 356 | } 357 | 358 | .btn { 359 | position: relative; 360 | display: flex; 361 | justify-content: center; 362 | align-items: center; 363 | width: 100%; 364 | height: 5vh; 365 | margin-top: .75vh; 366 | cursor: pointer; 367 | font-size: 2.5vh; 368 | background: var(--select-bg); 369 | color: var(--secondary-color); 370 | border: none; 371 | border-radius: 10px; 372 | font-weight: 400; 373 | text-overflow: ellipsis; 374 | white-space: nowrap; 375 | transition: color 0.1s linear, background-color 0.25s ease-in; 376 | } 377 | 378 | .btn:hover { 379 | background-color: var(--select-hover); 380 | } --------------------------------------------------------------------------------