├── .gitignore ├── src └── tailwind.css ├── tailwind.config.js ├── package.json ├── index.html └── dist ├── main.js └── tailwind.css /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /src/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: [ 3 | "*.html" 4 | ], 5 | mode: "jit", 6 | darkMode: false, // or 'media' or 'class' 7 | theme: { 8 | extend: {}, 9 | fontFamily: { 10 | sans: ["Fira sans", "sans-serif"] 11 | } 12 | }, 13 | variants: { 14 | extend: {}, 15 | }, 16 | plugins: [], 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "tailwindcss -i src/tailwind.css -o dist/tailwind.css --watch", 8 | "server": "live-server . --no-css-inject" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "tailwindcss": "^2.2.15" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Screen Recorder 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |

Screen Recorder

17 |
18 |
19 |
20 | 21 |
22 |
23 |

24 | Video recorder 25 |

26 | 27 | 28 | 29 |
30 | 33 | 36 |
37 | 38 | 50 |
51 |
52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /dist/main.js: -------------------------------------------------------------------------------- 1 | let stream = null, 2 | audio = null, 3 | mixedStream = null, 4 | chunks = [], 5 | recorder = null 6 | startButton = null, 7 | stopButton = null, 8 | downloadButton = null, 9 | recordedVideo = null; 10 | 11 | async function setupStream () { 12 | try { 13 | stream = await navigator.mediaDevices.getDisplayMedia({ 14 | video: true 15 | }); 16 | 17 | audio = await navigator.mediaDevices.getUserMedia({ 18 | audio: { 19 | echoCancellation: true, 20 | noiseSuppression: true, 21 | sampleRate: 44100, 22 | }, 23 | }); 24 | 25 | setupVideoFeedback(); 26 | } catch (err) { 27 | console.error(err) 28 | } 29 | } 30 | 31 | function setupVideoFeedback() { 32 | if (stream) { 33 | const video = document.querySelector('.video-feedback'); 34 | video.srcObject = stream; 35 | video.play(); 36 | } else { 37 | console.warn('No stream available'); 38 | } 39 | } 40 | 41 | async function startRecording () { 42 | await setupStream(); 43 | 44 | if (stream && audio) { 45 | mixedStream = new MediaStream([...stream.getTracks(), ...audio.getTracks()]); 46 | recorder = new MediaRecorder(mixedStream); 47 | recorder.ondataavailable = handleDataAvailable; 48 | recorder.onstop = handleStop; 49 | recorder.start(1000); 50 | 51 | startButton.disabled = true; 52 | stopButton.disabled = false; 53 | 54 | console.log('Recording started'); 55 | } else { 56 | console.warn('No stream available.'); 57 | } 58 | } 59 | 60 | function stopRecording () { 61 | recorder.stop(); 62 | 63 | startButton.disabled = false; 64 | stopButton.disabled = true; 65 | } 66 | 67 | function handleDataAvailable (e) { 68 | chunks.push(e.data); 69 | } 70 | 71 | function handleStop (e) { 72 | const blob = new Blob(chunks, { 'type' : 'video/mp4' }); 73 | chunks = []; 74 | 75 | downloadButton.href = URL.createObjectURL(blob); 76 | downloadButton.download = 'video.mp4'; 77 | downloadButton.disabled = false; 78 | 79 | recordedVideo.src = URL.createObjectURL(blob); 80 | recordedVideo.load(); 81 | recordedVideo.onloadeddata = function() { 82 | const rc = document.querySelector(".recorded-video-wrap"); 83 | rc.classList.remove("hidden"); 84 | rc.scrollIntoView({ behavior: "smooth", block: "start" }); 85 | 86 | recordedVideo.play(); 87 | } 88 | 89 | stream.getTracks().forEach((track) => track.stop()); 90 | audio.getTracks().forEach((track) => track.stop()); 91 | 92 | console.log('Recording stopped'); 93 | } 94 | 95 | window.addEventListener('load', () => { 96 | startButton = document.querySelector('.start-recording'); 97 | stopButton = document.querySelector('.stop-recording'); 98 | downloadButton = document.querySelector('.download-video'); 99 | recordedVideo = document.querySelector('.recorded-video'); 100 | 101 | startButton.addEventListener('click', startRecording); 102 | stopButton.addEventListener('click', stopRecording); 103 | }) -------------------------------------------------------------------------------- /dist/tailwind.css: -------------------------------------------------------------------------------- 1 | /*! tailwindcss v2.2.15 | MIT License | https://tailwindcss.com */ 2 | 3 | /*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */ 4 | 5 | /* 6 | Document 7 | ======== 8 | */ 9 | 10 | /** 11 | Use a better box model (opinionated). 12 | */ 13 | 14 | *, 15 | ::before, 16 | ::after { 17 | box-sizing: border-box; 18 | } 19 | 20 | /** 21 | Use a more readable tab size (opinionated). 22 | */ 23 | 24 | html { 25 | -moz-tab-size: 4; 26 | -o-tab-size: 4; 27 | tab-size: 4; 28 | } 29 | 30 | /** 31 | 1. Correct the line height in all browsers. 32 | 2. Prevent adjustments of font size after orientation changes in iOS. 33 | */ 34 | 35 | html { 36 | line-height: 1.15; 37 | /* 1 */ 38 | -webkit-text-size-adjust: 100%; 39 | /* 2 */ 40 | } 41 | 42 | /* 43 | Sections 44 | ======== 45 | */ 46 | 47 | /** 48 | Remove the margin in all browsers. 49 | */ 50 | 51 | body { 52 | margin: 0; 53 | } 54 | 55 | /** 56 | Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) 57 | */ 58 | 59 | body { 60 | font-family: 61 | system-ui, 62 | -apple-system, /* Firefox supports this but not yet `system-ui` */ 63 | 'Segoe UI', 64 | Roboto, 65 | Helvetica, 66 | Arial, 67 | sans-serif, 68 | 'Apple Color Emoji', 69 | 'Segoe UI Emoji'; 70 | } 71 | 72 | /* 73 | Grouping content 74 | ================ 75 | */ 76 | 77 | /** 78 | 1. Add the correct height in Firefox. 79 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 80 | */ 81 | 82 | hr { 83 | height: 0; 84 | /* 1 */ 85 | color: inherit; 86 | /* 2 */ 87 | } 88 | 89 | /* 90 | Text-level semantics 91 | ==================== 92 | */ 93 | 94 | /** 95 | Add the correct text decoration in Chrome, Edge, and Safari. 96 | */ 97 | 98 | abbr[title] { 99 | -webkit-text-decoration: underline dotted; 100 | text-decoration: underline dotted; 101 | } 102 | 103 | /** 104 | Add the correct font weight in Edge and Safari. 105 | */ 106 | 107 | b, 108 | strong { 109 | font-weight: bolder; 110 | } 111 | 112 | /** 113 | 1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) 114 | 2. Correct the odd 'em' font sizing in all browsers. 115 | */ 116 | 117 | code, 118 | kbd, 119 | samp, 120 | pre { 121 | font-family: 122 | ui-monospace, 123 | SFMono-Regular, 124 | Consolas, 125 | 'Liberation Mono', 126 | Menlo, 127 | monospace; 128 | /* 1 */ 129 | font-size: 1em; 130 | /* 2 */ 131 | } 132 | 133 | /** 134 | Add the correct font size in all browsers. 135 | */ 136 | 137 | small { 138 | font-size: 80%; 139 | } 140 | 141 | /** 142 | Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. 143 | */ 144 | 145 | sub, 146 | sup { 147 | font-size: 75%; 148 | line-height: 0; 149 | position: relative; 150 | vertical-align: baseline; 151 | } 152 | 153 | sub { 154 | bottom: -0.25em; 155 | } 156 | 157 | sup { 158 | top: -0.5em; 159 | } 160 | 161 | /* 162 | Tabular data 163 | ============ 164 | */ 165 | 166 | /** 167 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 168 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 169 | */ 170 | 171 | table { 172 | text-indent: 0; 173 | /* 1 */ 174 | border-color: inherit; 175 | /* 2 */ 176 | } 177 | 178 | /* 179 | Forms 180 | ===== 181 | */ 182 | 183 | /** 184 | 1. Change the font styles in all browsers. 185 | 2. Remove the margin in Firefox and Safari. 186 | */ 187 | 188 | button, 189 | input, 190 | optgroup, 191 | select, 192 | textarea { 193 | font-family: inherit; 194 | /* 1 */ 195 | font-size: 100%; 196 | /* 1 */ 197 | line-height: 1.15; 198 | /* 1 */ 199 | margin: 0; 200 | /* 2 */ 201 | } 202 | 203 | /** 204 | Remove the inheritance of text transform in Edge and Firefox. 205 | 1. Remove the inheritance of text transform in Firefox. 206 | */ 207 | 208 | button, 209 | select { 210 | /* 1 */ 211 | text-transform: none; 212 | } 213 | 214 | /** 215 | Correct the inability to style clickable types in iOS and Safari. 216 | */ 217 | 218 | button, 219 | [type='button'], 220 | [type='reset'], 221 | [type='submit'] { 222 | -webkit-appearance: button; 223 | } 224 | 225 | /** 226 | Remove the inner border and padding in Firefox. 227 | */ 228 | 229 | ::-moz-focus-inner { 230 | border-style: none; 231 | padding: 0; 232 | } 233 | 234 | /** 235 | Restore the focus styles unset by the previous rule. 236 | */ 237 | 238 | :-moz-focusring { 239 | outline: 1px dotted ButtonText; 240 | } 241 | 242 | /** 243 | Remove the additional ':invalid' styles in Firefox. 244 | See: https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737 245 | */ 246 | 247 | :-moz-ui-invalid { 248 | box-shadow: none; 249 | } 250 | 251 | /** 252 | Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers. 253 | */ 254 | 255 | legend { 256 | padding: 0; 257 | } 258 | 259 | /** 260 | Add the correct vertical alignment in Chrome and Firefox. 261 | */ 262 | 263 | progress { 264 | vertical-align: baseline; 265 | } 266 | 267 | /** 268 | Correct the cursor style of increment and decrement buttons in Safari. 269 | */ 270 | 271 | ::-webkit-inner-spin-button, 272 | ::-webkit-outer-spin-button { 273 | height: auto; 274 | } 275 | 276 | /** 277 | 1. Correct the odd appearance in Chrome and Safari. 278 | 2. Correct the outline style in Safari. 279 | */ 280 | 281 | [type='search'] { 282 | -webkit-appearance: textfield; 283 | /* 1 */ 284 | outline-offset: -2px; 285 | /* 2 */ 286 | } 287 | 288 | /** 289 | Remove the inner padding in Chrome and Safari on macOS. 290 | */ 291 | 292 | ::-webkit-search-decoration { 293 | -webkit-appearance: none; 294 | } 295 | 296 | /** 297 | 1. Correct the inability to style clickable types in iOS and Safari. 298 | 2. Change font properties to 'inherit' in Safari. 299 | */ 300 | 301 | ::-webkit-file-upload-button { 302 | -webkit-appearance: button; 303 | /* 1 */ 304 | font: inherit; 305 | /* 2 */ 306 | } 307 | 308 | /* 309 | Interactive 310 | =========== 311 | */ 312 | 313 | /* 314 | Add the correct display in Chrome and Safari. 315 | */ 316 | 317 | summary { 318 | display: list-item; 319 | } 320 | 321 | /** 322 | * Manually forked from SUIT CSS Base: https://github.com/suitcss/base 323 | * A thin layer on top of normalize.css that provides a starting point more 324 | * suitable for web applications. 325 | */ 326 | 327 | /** 328 | * Removes the default spacing and border for appropriate elements. 329 | */ 330 | 331 | blockquote, 332 | dl, 333 | dd, 334 | h1, 335 | h2, 336 | h3, 337 | h4, 338 | h5, 339 | h6, 340 | hr, 341 | figure, 342 | p, 343 | pre { 344 | margin: 0; 345 | } 346 | 347 | button { 348 | background-color: transparent; 349 | background-image: none; 350 | } 351 | 352 | fieldset { 353 | margin: 0; 354 | padding: 0; 355 | } 356 | 357 | ol, 358 | ul { 359 | list-style: none; 360 | margin: 0; 361 | padding: 0; 362 | } 363 | 364 | /** 365 | * Tailwind custom reset styles 366 | */ 367 | 368 | /** 369 | * 1. Use the user's configured `sans` font-family (with Tailwind's default 370 | * sans-serif font stack as a fallback) as a sane default. 371 | * 2. Use Tailwind's default "normal" line-height so the user isn't forced 372 | * to override it to ensure consistency even when using the default theme. 373 | */ 374 | 375 | html { 376 | font-family: Fira sans, sans-serif; 377 | /* 1 */ 378 | line-height: 1.5; 379 | /* 2 */ 380 | } 381 | 382 | /** 383 | * Inherit font-family and line-height from `html` so users can set them as 384 | * a class directly on the `html` element. 385 | */ 386 | 387 | body { 388 | font-family: inherit; 389 | line-height: inherit; 390 | } 391 | 392 | /** 393 | * 1. Prevent padding and border from affecting element width. 394 | * 395 | * We used to set this in the html element and inherit from 396 | * the parent element for everything else. This caused issues 397 | * in shadow-dom-enhanced elements like
where the content 398 | * is wrapped by a div with box-sizing set to `content-box`. 399 | * 400 | * https://github.com/mozdevs/cssremedy/issues/4 401 | * 402 | * 403 | * 2. Allow adding a border to an element by just adding a border-width. 404 | * 405 | * By default, the way the browser specifies that an element should have no 406 | * border is by setting it's border-style to `none` in the user-agent 407 | * stylesheet. 408 | * 409 | * In order to easily add borders to elements by just setting the `border-width` 410 | * property, we change the default border-style for all elements to `solid`, and 411 | * use border-width to hide them instead. This way our `border` utilities only 412 | * need to set the `border-width` property instead of the entire `border` 413 | * shorthand, making our border utilities much more straightforward to compose. 414 | * 415 | * https://github.com/tailwindcss/tailwindcss/pull/116 416 | */ 417 | 418 | *, 419 | ::before, 420 | ::after { 421 | box-sizing: border-box; 422 | /* 1 */ 423 | border-width: 0; 424 | /* 2 */ 425 | border-style: solid; 426 | /* 2 */ 427 | border-color: currentColor; 428 | /* 2 */ 429 | } 430 | 431 | /* 432 | * Ensure horizontal rules are visible by default 433 | */ 434 | 435 | hr { 436 | border-top-width: 1px; 437 | } 438 | 439 | /** 440 | * Undo the `border-style: none` reset that Normalize applies to images so that 441 | * our `border-{width}` utilities have the expected effect. 442 | * 443 | * The Normalize reset is unnecessary for us since we default the border-width 444 | * to 0 on all elements. 445 | * 446 | * https://github.com/tailwindcss/tailwindcss/issues/362 447 | */ 448 | 449 | img { 450 | border-style: solid; 451 | } 452 | 453 | textarea { 454 | resize: vertical; 455 | } 456 | 457 | input::-moz-placeholder, textarea::-moz-placeholder { 458 | opacity: 1; 459 | color: #9ca3af; 460 | } 461 | 462 | input:-ms-input-placeholder, textarea:-ms-input-placeholder { 463 | opacity: 1; 464 | color: #9ca3af; 465 | } 466 | 467 | input::placeholder, 468 | textarea::placeholder { 469 | opacity: 1; 470 | color: #9ca3af; 471 | } 472 | 473 | button, 474 | [role="button"] { 475 | cursor: pointer; 476 | } 477 | 478 | /** 479 | * Override legacy focus reset from Normalize with modern Firefox focus styles. 480 | * 481 | * This is actually an improvement over the new defaults in Firefox in our testing, 482 | * as it triggers the better focus styles even for links, which still use a dotted 483 | * outline in Firefox by default. 484 | */ 485 | 486 | :-moz-focusring { 487 | outline: auto; 488 | } 489 | 490 | table { 491 | border-collapse: collapse; 492 | } 493 | 494 | h1, 495 | h2, 496 | h3, 497 | h4, 498 | h5, 499 | h6 { 500 | font-size: inherit; 501 | font-weight: inherit; 502 | } 503 | 504 | /** 505 | * Reset links to optimize for opt-in styling instead of 506 | * opt-out. 507 | */ 508 | 509 | a { 510 | color: inherit; 511 | text-decoration: inherit; 512 | } 513 | 514 | /** 515 | * Reset form element properties that are easy to forget to 516 | * style explicitly so you don't inadvertently introduce 517 | * styles that deviate from your design system. These styles 518 | * supplement a partial reset that is already applied by 519 | * normalize.css. 520 | */ 521 | 522 | button, 523 | input, 524 | optgroup, 525 | select, 526 | textarea { 527 | padding: 0; 528 | line-height: inherit; 529 | color: inherit; 530 | } 531 | 532 | /** 533 | * Use the configured 'mono' font family for elements that 534 | * are expected to be rendered with a monospace font, falling 535 | * back to the system monospace stack if there is no configured 536 | * 'mono' font family. 537 | */ 538 | 539 | pre, 540 | code, 541 | kbd, 542 | samp { 543 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 544 | } 545 | 546 | /** 547 | * 1. Make replaced elements `display: block` by default as that's 548 | * the behavior you want almost all of the time. Inspired by 549 | * CSS Remedy, with `svg` added as well. 550 | * 551 | * https://github.com/mozdevs/cssremedy/issues/14 552 | * 553 | * 2. Add `vertical-align: middle` to align replaced elements more 554 | * sensibly by default when overriding `display` by adding a 555 | * utility like `inline`. 556 | * 557 | * This can trigger a poorly considered linting error in some 558 | * tools but is included by design. 559 | * 560 | * https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210 561 | */ 562 | 563 | img, 564 | svg, 565 | video, 566 | canvas, 567 | audio, 568 | iframe, 569 | embed, 570 | object { 571 | display: block; 572 | /* 1 */ 573 | vertical-align: middle; 574 | /* 2 */ 575 | } 576 | 577 | /** 578 | * Constrain images and videos to the parent width and preserve 579 | * their intrinsic aspect ratio. 580 | * 581 | * https://github.com/mozdevs/cssremedy/issues/14 582 | */ 583 | 584 | img, 585 | video { 586 | max-width: 100%; 587 | height: auto; 588 | } 589 | 590 | /** 591 | * Ensure the default browser behavior of the `hidden` attribute. 592 | */ 593 | 594 | [hidden] { 595 | display: none; 596 | } 597 | 598 | .container { 599 | width: 100%; 600 | } 601 | 602 | @media (min-width: 640px) { 603 | .container { 604 | max-width: 640px; 605 | } 606 | } 607 | 608 | @media (min-width: 768px) { 609 | .container { 610 | max-width: 768px; 611 | } 612 | } 613 | 614 | @media (min-width: 1024px) { 615 | .container { 616 | max-width: 1024px; 617 | } 618 | } 619 | 620 | @media (min-width: 1280px) { 621 | .container { 622 | max-width: 1280px; 623 | } 624 | } 625 | 626 | @media (min-width: 1536px) { 627 | .container { 628 | max-width: 1536px; 629 | } 630 | } 631 | 632 | .mx-auto { 633 | margin-left: auto; 634 | margin-right: auto; 635 | } 636 | 637 | .-mx-4 { 638 | margin-left: -1rem; 639 | margin-right: -1rem; 640 | } 641 | 642 | .mx-4 { 643 | margin-left: 1rem; 644 | margin-right: 1rem; 645 | } 646 | 647 | .my-8 { 648 | margin-top: 2rem; 649 | margin-bottom: 2rem; 650 | } 651 | 652 | .mb-8 { 653 | margin-bottom: 2rem; 654 | } 655 | 656 | .mb-4 { 657 | margin-bottom: 1rem; 658 | } 659 | 660 | .mt-8 { 661 | margin-top: 2rem; 662 | } 663 | 664 | .flex { 665 | display: flex; 666 | } 667 | 668 | .hidden { 669 | display: none; 670 | } 671 | 672 | .h-80 { 673 | height: 20rem; 674 | } 675 | 676 | .h-auto { 677 | height: auto; 678 | } 679 | 680 | .w-full { 681 | width: 100%; 682 | } 683 | 684 | .flex-1 { 685 | flex: 1 1 0%; 686 | } 687 | 688 | .flex-wrap { 689 | flex-wrap: wrap; 690 | } 691 | 692 | .items-center { 693 | align-items: center; 694 | } 695 | 696 | .justify-center { 697 | justify-content: center; 698 | } 699 | 700 | .overflow-hidden { 701 | overflow: hidden; 702 | } 703 | 704 | .bg-gray-800 { 705 | --tw-bg-opacity: 1; 706 | background-color: rgba(31, 41, 55, var(--tw-bg-opacity)); 707 | } 708 | 709 | .bg-gray-900 { 710 | --tw-bg-opacity: 1; 711 | background-color: rgba(17, 24, 39, var(--tw-bg-opacity)); 712 | } 713 | 714 | .bg-black { 715 | --tw-bg-opacity: 1; 716 | background-color: rgba(0, 0, 0, var(--tw-bg-opacity)); 717 | } 718 | 719 | .bg-gradient-to-br { 720 | background-image: linear-gradient(to bottom right, var(--tw-gradient-stops)); 721 | } 722 | 723 | .from-purple-500 { 724 | --tw-gradient-from: #8b5cf6; 725 | --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, rgba(139, 92, 246, 0)); 726 | } 727 | 728 | .to-pink-500 { 729 | --tw-gradient-to: #ec4899; 730 | } 731 | 732 | .p-4 { 733 | padding: 1rem; 734 | } 735 | 736 | .py-4 { 737 | padding-top: 1rem; 738 | padding-bottom: 1rem; 739 | } 740 | 741 | .py-8 { 742 | padding-top: 2rem; 743 | padding-bottom: 2rem; 744 | } 745 | 746 | .px-4 { 747 | padding-left: 1rem; 748 | padding-right: 1rem; 749 | } 750 | 751 | .text-center { 752 | text-align: center; 753 | } 754 | 755 | .text-2xl { 756 | font-size: 1.5rem; 757 | line-height: 2rem; 758 | } 759 | 760 | .text-xl { 761 | font-size: 1.25rem; 762 | line-height: 1.75rem; 763 | } 764 | 765 | .text-lg { 766 | font-size: 1.125rem; 767 | line-height: 1.75rem; 768 | } 769 | 770 | .font-bold { 771 | font-weight: 700; 772 | } 773 | 774 | .font-light { 775 | font-weight: 300; 776 | } 777 | 778 | .uppercase { 779 | text-transform: uppercase; 780 | } 781 | 782 | .text-white { 783 | --tw-text-opacity: 1; 784 | color: rgba(255, 255, 255, var(--tw-text-opacity)); 785 | } 786 | 787 | .text-gray-500 { 788 | --tw-text-opacity: 1; 789 | color: rgba(107, 114, 128, var(--tw-text-opacity)); 790 | } 791 | 792 | .transition-all { 793 | transition-property: all; 794 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 795 | transition-duration: 150ms; 796 | } 797 | 798 | .duration-300 { 799 | transition-duration: 300ms; 800 | } 801 | 802 | .hover\:from-purple-600:hover { 803 | --tw-gradient-from: #7c3aed; 804 | --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, rgba(124, 58, 237, 0)); 805 | } 806 | 807 | .hover\:to-pink-600:hover { 808 | --tw-gradient-to: #db2777; 809 | } 810 | 811 | .hover\:opacity-90:hover { 812 | opacity: 0.9; 813 | } 814 | 815 | .disabled\:opacity-50:disabled { 816 | opacity: 0.5; 817 | } --------------------------------------------------------------------------------