this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add sidebar

+2196 -347
+749 -14
mast-react-vite/package-lock.json
··· 9 9 "version": "0.0.0", 10 10 "dependencies": { 11 11 "@radix-ui/react-checkbox": "^1.1.2", 12 + "@radix-ui/react-dialog": "^1.1.6", 12 13 "@radix-ui/react-icons": "^1.3.0", 13 14 "@radix-ui/react-scroll-area": "^1.2.3", 14 15 "@radix-ui/react-separator": "^1.1.2", 15 16 "@radix-ui/react-slot": "^1.1.2", 16 17 "@radix-ui/react-toggle": "^1.1.2", 17 18 "@radix-ui/react-toggle-group": "^1.1.2", 19 + "@radix-ui/react-tooltip": "^1.1.8", 18 20 "@tanstack/react-table": "^8.20.5", 19 21 "@vlcn.io/react": "^3.1.0", 20 22 "@vlcn.io/rx-tbl": "^0.15.0", 21 23 "@vlcn.io/ws-browserdb": "^0.2.0", 22 - "class-variance-authority": "^0.7.0", 24 + "class-variance-authority": "^0.7.1", 23 25 "clsx": "^2.1.1", 24 26 "lucide-react": "^0.454.0", 25 27 "react": "^18.3.1", ··· 199 201 "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 200 202 } 201 203 }, 204 + "node_modules/@floating-ui/core": { 205 + "version": "1.6.9", 206 + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", 207 + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", 208 + "dependencies": { 209 + "@floating-ui/utils": "^0.2.9" 210 + } 211 + }, 212 + "node_modules/@floating-ui/dom": { 213 + "version": "1.6.13", 214 + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", 215 + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", 216 + "dependencies": { 217 + "@floating-ui/core": "^1.6.0", 218 + "@floating-ui/utils": "^0.2.9" 219 + } 220 + }, 221 + "node_modules/@floating-ui/react-dom": { 222 + "version": "2.1.2", 223 + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", 224 + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", 225 + "dependencies": { 226 + "@floating-ui/dom": "^1.0.0" 227 + }, 228 + "peerDependencies": { 229 + "react": ">=16.8.0", 230 + "react-dom": ">=16.8.0" 231 + } 232 + }, 233 + "node_modules/@floating-ui/utils": { 234 + "version": "0.2.9", 235 + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", 236 + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==" 237 + }, 202 238 "node_modules/@humanfs/core": { 203 239 "version": "0.19.1", 204 240 "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", ··· 357 393 "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", 358 394 "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" 359 395 }, 396 + "node_modules/@radix-ui/react-arrow": { 397 + "version": "1.1.2", 398 + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz", 399 + "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==", 400 + "dependencies": { 401 + "@radix-ui/react-primitive": "2.0.2" 402 + }, 403 + "peerDependencies": { 404 + "@types/react": "*", 405 + "@types/react-dom": "*", 406 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 407 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 408 + }, 409 + "peerDependenciesMeta": { 410 + "@types/react": { 411 + "optional": true 412 + }, 413 + "@types/react-dom": { 414 + "optional": true 415 + } 416 + } 417 + }, 418 + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { 419 + "version": "2.0.2", 420 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", 421 + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", 422 + "dependencies": { 423 + "@radix-ui/react-slot": "1.1.2" 424 + }, 425 + "peerDependencies": { 426 + "@types/react": "*", 427 + "@types/react-dom": "*", 428 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 429 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 430 + }, 431 + "peerDependenciesMeta": { 432 + "@types/react": { 433 + "optional": true 434 + }, 435 + "@types/react-dom": { 436 + "optional": true 437 + } 438 + } 439 + }, 360 440 "node_modules/@radix-ui/react-checkbox": { 361 441 "version": "1.1.2", 362 442 "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.2.tgz", ··· 475 555 } 476 556 } 477 557 }, 558 + "node_modules/@radix-ui/react-dialog": { 559 + "version": "1.1.6", 560 + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz", 561 + "integrity": "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==", 562 + "dependencies": { 563 + "@radix-ui/primitive": "1.1.1", 564 + "@radix-ui/react-compose-refs": "1.1.1", 565 + "@radix-ui/react-context": "1.1.1", 566 + "@radix-ui/react-dismissable-layer": "1.1.5", 567 + "@radix-ui/react-focus-guards": "1.1.1", 568 + "@radix-ui/react-focus-scope": "1.1.2", 569 + "@radix-ui/react-id": "1.1.0", 570 + "@radix-ui/react-portal": "1.1.4", 571 + "@radix-ui/react-presence": "1.1.2", 572 + "@radix-ui/react-primitive": "2.0.2", 573 + "@radix-ui/react-slot": "1.1.2", 574 + "@radix-ui/react-use-controllable-state": "1.1.0", 575 + "aria-hidden": "^1.2.4", 576 + "react-remove-scroll": "^2.6.3" 577 + }, 578 + "peerDependencies": { 579 + "@types/react": "*", 580 + "@types/react-dom": "*", 581 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 582 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 583 + }, 584 + "peerDependenciesMeta": { 585 + "@types/react": { 586 + "optional": true 587 + }, 588 + "@types/react-dom": { 589 + "optional": true 590 + } 591 + } 592 + }, 593 + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/primitive": { 594 + "version": "1.1.1", 595 + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", 596 + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==" 597 + }, 598 + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-compose-refs": { 599 + "version": "1.1.1", 600 + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", 601 + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", 602 + "peerDependencies": { 603 + "@types/react": "*", 604 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 605 + }, 606 + "peerDependenciesMeta": { 607 + "@types/react": { 608 + "optional": true 609 + } 610 + } 611 + }, 612 + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": { 613 + "version": "1.1.2", 614 + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", 615 + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", 616 + "dependencies": { 617 + "@radix-ui/react-compose-refs": "1.1.1", 618 + "@radix-ui/react-use-layout-effect": "1.1.0" 619 + }, 620 + "peerDependencies": { 621 + "@types/react": "*", 622 + "@types/react-dom": "*", 623 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 624 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 625 + }, 626 + "peerDependenciesMeta": { 627 + "@types/react": { 628 + "optional": true 629 + }, 630 + "@types/react-dom": { 631 + "optional": true 632 + } 633 + } 634 + }, 635 + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { 636 + "version": "2.0.2", 637 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", 638 + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", 639 + "dependencies": { 640 + "@radix-ui/react-slot": "1.1.2" 641 + }, 642 + "peerDependencies": { 643 + "@types/react": "*", 644 + "@types/react-dom": "*", 645 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 646 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 647 + }, 648 + "peerDependenciesMeta": { 649 + "@types/react": { 650 + "optional": true 651 + }, 652 + "@types/react-dom": { 653 + "optional": true 654 + } 655 + } 656 + }, 478 657 "node_modules/@radix-ui/react-direction": { 479 658 "version": "1.1.0", 480 659 "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", ··· 489 668 } 490 669 } 491 670 }, 671 + "node_modules/@radix-ui/react-dismissable-layer": { 672 + "version": "1.1.5", 673 + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz", 674 + "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==", 675 + "dependencies": { 676 + "@radix-ui/primitive": "1.1.1", 677 + "@radix-ui/react-compose-refs": "1.1.1", 678 + "@radix-ui/react-primitive": "2.0.2", 679 + "@radix-ui/react-use-callback-ref": "1.1.0", 680 + "@radix-ui/react-use-escape-keydown": "1.1.0" 681 + }, 682 + "peerDependencies": { 683 + "@types/react": "*", 684 + "@types/react-dom": "*", 685 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 686 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 687 + }, 688 + "peerDependenciesMeta": { 689 + "@types/react": { 690 + "optional": true 691 + }, 692 + "@types/react-dom": { 693 + "optional": true 694 + } 695 + } 696 + }, 697 + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/primitive": { 698 + "version": "1.1.1", 699 + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", 700 + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==" 701 + }, 702 + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-compose-refs": { 703 + "version": "1.1.1", 704 + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", 705 + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", 706 + "peerDependencies": { 707 + "@types/react": "*", 708 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 709 + }, 710 + "peerDependenciesMeta": { 711 + "@types/react": { 712 + "optional": true 713 + } 714 + } 715 + }, 716 + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-primitive": { 717 + "version": "2.0.2", 718 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", 719 + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", 720 + "dependencies": { 721 + "@radix-ui/react-slot": "1.1.2" 722 + }, 723 + "peerDependencies": { 724 + "@types/react": "*", 725 + "@types/react-dom": "*", 726 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 727 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 728 + }, 729 + "peerDependenciesMeta": { 730 + "@types/react": { 731 + "optional": true 732 + }, 733 + "@types/react-dom": { 734 + "optional": true 735 + } 736 + } 737 + }, 738 + "node_modules/@radix-ui/react-focus-guards": { 739 + "version": "1.1.1", 740 + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", 741 + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", 742 + "peerDependencies": { 743 + "@types/react": "*", 744 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 745 + }, 746 + "peerDependenciesMeta": { 747 + "@types/react": { 748 + "optional": true 749 + } 750 + } 751 + }, 752 + "node_modules/@radix-ui/react-focus-scope": { 753 + "version": "1.1.2", 754 + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz", 755 + "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==", 756 + "dependencies": { 757 + "@radix-ui/react-compose-refs": "1.1.1", 758 + "@radix-ui/react-primitive": "2.0.2", 759 + "@radix-ui/react-use-callback-ref": "1.1.0" 760 + }, 761 + "peerDependencies": { 762 + "@types/react": "*", 763 + "@types/react-dom": "*", 764 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 765 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 766 + }, 767 + "peerDependenciesMeta": { 768 + "@types/react": { 769 + "optional": true 770 + }, 771 + "@types/react-dom": { 772 + "optional": true 773 + } 774 + } 775 + }, 776 + "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-compose-refs": { 777 + "version": "1.1.1", 778 + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", 779 + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", 780 + "peerDependencies": { 781 + "@types/react": "*", 782 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 783 + }, 784 + "peerDependenciesMeta": { 785 + "@types/react": { 786 + "optional": true 787 + } 788 + } 789 + }, 790 + "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-primitive": { 791 + "version": "2.0.2", 792 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", 793 + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", 794 + "dependencies": { 795 + "@radix-ui/react-slot": "1.1.2" 796 + }, 797 + "peerDependencies": { 798 + "@types/react": "*", 799 + "@types/react-dom": "*", 800 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 801 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 802 + }, 803 + "peerDependenciesMeta": { 804 + "@types/react": { 805 + "optional": true 806 + }, 807 + "@types/react-dom": { 808 + "optional": true 809 + } 810 + } 811 + }, 492 812 "node_modules/@radix-ui/react-icons": { 493 813 "version": "1.3.0", 494 814 "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz", ··· 514 834 } 515 835 } 516 836 }, 837 + "node_modules/@radix-ui/react-popper": { 838 + "version": "1.2.2", 839 + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz", 840 + "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==", 841 + "dependencies": { 842 + "@floating-ui/react-dom": "^2.0.0", 843 + "@radix-ui/react-arrow": "1.1.2", 844 + "@radix-ui/react-compose-refs": "1.1.1", 845 + "@radix-ui/react-context": "1.1.1", 846 + "@radix-ui/react-primitive": "2.0.2", 847 + "@radix-ui/react-use-callback-ref": "1.1.0", 848 + "@radix-ui/react-use-layout-effect": "1.1.0", 849 + "@radix-ui/react-use-rect": "1.1.0", 850 + "@radix-ui/react-use-size": "1.1.0", 851 + "@radix-ui/rect": "1.1.0" 852 + }, 853 + "peerDependencies": { 854 + "@types/react": "*", 855 + "@types/react-dom": "*", 856 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 857 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 858 + }, 859 + "peerDependenciesMeta": { 860 + "@types/react": { 861 + "optional": true 862 + }, 863 + "@types/react-dom": { 864 + "optional": true 865 + } 866 + } 867 + }, 868 + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-compose-refs": { 869 + "version": "1.1.1", 870 + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", 871 + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", 872 + "peerDependencies": { 873 + "@types/react": "*", 874 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 875 + }, 876 + "peerDependenciesMeta": { 877 + "@types/react": { 878 + "optional": true 879 + } 880 + } 881 + }, 882 + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { 883 + "version": "2.0.2", 884 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", 885 + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", 886 + "dependencies": { 887 + "@radix-ui/react-slot": "1.1.2" 888 + }, 889 + "peerDependencies": { 890 + "@types/react": "*", 891 + "@types/react-dom": "*", 892 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 893 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 894 + }, 895 + "peerDependenciesMeta": { 896 + "@types/react": { 897 + "optional": true 898 + }, 899 + "@types/react-dom": { 900 + "optional": true 901 + } 902 + } 903 + }, 904 + "node_modules/@radix-ui/react-portal": { 905 + "version": "1.1.4", 906 + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz", 907 + "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==", 908 + "dependencies": { 909 + "@radix-ui/react-primitive": "2.0.2", 910 + "@radix-ui/react-use-layout-effect": "1.1.0" 911 + }, 912 + "peerDependencies": { 913 + "@types/react": "*", 914 + "@types/react-dom": "*", 915 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 916 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 917 + }, 918 + "peerDependenciesMeta": { 919 + "@types/react": { 920 + "optional": true 921 + }, 922 + "@types/react-dom": { 923 + "optional": true 924 + } 925 + } 926 + }, 927 + "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-primitive": { 928 + "version": "2.0.2", 929 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", 930 + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", 931 + "dependencies": { 932 + "@radix-ui/react-slot": "1.1.2" 933 + }, 934 + "peerDependencies": { 935 + "@types/react": "*", 936 + "@types/react-dom": "*", 937 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 938 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 939 + }, 940 + "peerDependenciesMeta": { 941 + "@types/react": { 942 + "optional": true 943 + }, 944 + "@types/react-dom": { 945 + "optional": true 946 + } 947 + } 948 + }, 517 949 "node_modules/@radix-ui/react-presence": { 518 950 "version": "1.1.1", 519 951 "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", ··· 922 1354 } 923 1355 } 924 1356 }, 1357 + "node_modules/@radix-ui/react-tooltip": { 1358 + "version": "1.1.8", 1359 + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.8.tgz", 1360 + "integrity": "sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA==", 1361 + "dependencies": { 1362 + "@radix-ui/primitive": "1.1.1", 1363 + "@radix-ui/react-compose-refs": "1.1.1", 1364 + "@radix-ui/react-context": "1.1.1", 1365 + "@radix-ui/react-dismissable-layer": "1.1.5", 1366 + "@radix-ui/react-id": "1.1.0", 1367 + "@radix-ui/react-popper": "1.2.2", 1368 + "@radix-ui/react-portal": "1.1.4", 1369 + "@radix-ui/react-presence": "1.1.2", 1370 + "@radix-ui/react-primitive": "2.0.2", 1371 + "@radix-ui/react-slot": "1.1.2", 1372 + "@radix-ui/react-use-controllable-state": "1.1.0", 1373 + "@radix-ui/react-visually-hidden": "1.1.2" 1374 + }, 1375 + "peerDependencies": { 1376 + "@types/react": "*", 1377 + "@types/react-dom": "*", 1378 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 1379 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 1380 + }, 1381 + "peerDependenciesMeta": { 1382 + "@types/react": { 1383 + "optional": true 1384 + }, 1385 + "@types/react-dom": { 1386 + "optional": true 1387 + } 1388 + } 1389 + }, 1390 + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/primitive": { 1391 + "version": "1.1.1", 1392 + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", 1393 + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==" 1394 + }, 1395 + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-compose-refs": { 1396 + "version": "1.1.1", 1397 + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", 1398 + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", 1399 + "peerDependencies": { 1400 + "@types/react": "*", 1401 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 1402 + }, 1403 + "peerDependenciesMeta": { 1404 + "@types/react": { 1405 + "optional": true 1406 + } 1407 + } 1408 + }, 1409 + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-presence": { 1410 + "version": "1.1.2", 1411 + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", 1412 + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", 1413 + "dependencies": { 1414 + "@radix-ui/react-compose-refs": "1.1.1", 1415 + "@radix-ui/react-use-layout-effect": "1.1.0" 1416 + }, 1417 + "peerDependencies": { 1418 + "@types/react": "*", 1419 + "@types/react-dom": "*", 1420 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 1421 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 1422 + }, 1423 + "peerDependenciesMeta": { 1424 + "@types/react": { 1425 + "optional": true 1426 + }, 1427 + "@types/react-dom": { 1428 + "optional": true 1429 + } 1430 + } 1431 + }, 1432 + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { 1433 + "version": "2.0.2", 1434 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", 1435 + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", 1436 + "dependencies": { 1437 + "@radix-ui/react-slot": "1.1.2" 1438 + }, 1439 + "peerDependencies": { 1440 + "@types/react": "*", 1441 + "@types/react-dom": "*", 1442 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 1443 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 1444 + }, 1445 + "peerDependenciesMeta": { 1446 + "@types/react": { 1447 + "optional": true 1448 + }, 1449 + "@types/react-dom": { 1450 + "optional": true 1451 + } 1452 + } 1453 + }, 925 1454 "node_modules/@radix-ui/react-use-callback-ref": { 926 1455 "version": "1.1.0", 927 1456 "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", ··· 953 1482 } 954 1483 } 955 1484 }, 1485 + "node_modules/@radix-ui/react-use-escape-keydown": { 1486 + "version": "1.1.0", 1487 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", 1488 + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", 1489 + "dependencies": { 1490 + "@radix-ui/react-use-callback-ref": "1.1.0" 1491 + }, 1492 + "peerDependencies": { 1493 + "@types/react": "*", 1494 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 1495 + }, 1496 + "peerDependenciesMeta": { 1497 + "@types/react": { 1498 + "optional": true 1499 + } 1500 + } 1501 + }, 956 1502 "node_modules/@radix-ui/react-use-layout-effect": { 957 1503 "version": "1.1.0", 958 1504 "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", ··· 981 1527 } 982 1528 } 983 1529 }, 1530 + "node_modules/@radix-ui/react-use-rect": { 1531 + "version": "1.1.0", 1532 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", 1533 + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", 1534 + "dependencies": { 1535 + "@radix-ui/rect": "1.1.0" 1536 + }, 1537 + "peerDependencies": { 1538 + "@types/react": "*", 1539 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 1540 + }, 1541 + "peerDependenciesMeta": { 1542 + "@types/react": { 1543 + "optional": true 1544 + } 1545 + } 1546 + }, 984 1547 "node_modules/@radix-ui/react-use-size": { 985 1548 "version": "1.1.0", 986 1549 "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", ··· 998 1561 } 999 1562 } 1000 1563 }, 1564 + "node_modules/@radix-ui/react-visually-hidden": { 1565 + "version": "1.1.2", 1566 + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz", 1567 + "integrity": "sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==", 1568 + "dependencies": { 1569 + "@radix-ui/react-primitive": "2.0.2" 1570 + }, 1571 + "peerDependencies": { 1572 + "@types/react": "*", 1573 + "@types/react-dom": "*", 1574 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 1575 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 1576 + }, 1577 + "peerDependenciesMeta": { 1578 + "@types/react": { 1579 + "optional": true 1580 + }, 1581 + "@types/react-dom": { 1582 + "optional": true 1583 + } 1584 + } 1585 + }, 1586 + "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": { 1587 + "version": "2.0.2", 1588 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", 1589 + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", 1590 + "dependencies": { 1591 + "@radix-ui/react-slot": "1.1.2" 1592 + }, 1593 + "peerDependencies": { 1594 + "@types/react": "*", 1595 + "@types/react-dom": "*", 1596 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 1597 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 1598 + }, 1599 + "peerDependenciesMeta": { 1600 + "@types/react": { 1601 + "optional": true 1602 + }, 1603 + "@types/react-dom": { 1604 + "optional": true 1605 + } 1606 + } 1607 + }, 1608 + "node_modules/@radix-ui/rect": { 1609 + "version": "1.1.0", 1610 + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", 1611 + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" 1612 + }, 1001 1613 "node_modules/@rollup/rollup-linux-x64-gnu": { 1002 1614 "version": "4.24.2", 1003 1615 "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.2.tgz", ··· 1593 2205 "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 1594 2206 "dev": true 1595 2207 }, 2208 + "node_modules/aria-hidden": { 2209 + "version": "1.2.4", 2210 + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", 2211 + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", 2212 + "dependencies": { 2213 + "tslib": "^2.0.0" 2214 + }, 2215 + "engines": { 2216 + "node": ">=10" 2217 + } 2218 + }, 1596 2219 "node_modules/async-mutex": { 1597 2220 "version": "0.4.1", 1598 2221 "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.4.1.tgz", ··· 1795 2418 } 1796 2419 }, 1797 2420 "node_modules/class-variance-authority": { 1798 - "version": "0.7.0", 1799 - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", 1800 - "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", 2421 + "version": "0.7.1", 2422 + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", 2423 + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", 1801 2424 "dependencies": { 1802 - "clsx": "2.0.0" 2425 + "clsx": "^2.1.1" 1803 2426 }, 1804 2427 "funding": { 1805 - "url": "https://joebell.co.uk" 1806 - } 1807 - }, 1808 - "node_modules/class-variance-authority/node_modules/clsx": { 1809 - "version": "2.0.0", 1810 - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", 1811 - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", 1812 - "engines": { 1813 - "node": ">=6" 2428 + "url": "https://polar.sh/cva" 1814 2429 } 1815 2430 }, 1816 2431 "node_modules/clsx": { ··· 1908 2523 "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 1909 2524 "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 1910 2525 "dev": true 2526 + }, 2527 + "node_modules/detect-node-es": { 2528 + "version": "1.1.0", 2529 + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", 2530 + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" 1911 2531 }, 1912 2532 "node_modules/didyoumean": { 1913 2533 "version": "1.2.2", ··· 2306 2926 "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 2307 2927 "funding": { 2308 2928 "url": "https://github.com/sponsors/ljharb" 2929 + } 2930 + }, 2931 + "node_modules/get-nonce": { 2932 + "version": "1.0.1", 2933 + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", 2934 + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", 2935 + "engines": { 2936 + "node": ">=6" 2309 2937 } 2310 2938 }, 2311 2939 "node_modules/glob": { ··· 3121 3749 "react": "^18.3.1" 3122 3750 } 3123 3751 }, 3752 + "node_modules/react-remove-scroll": { 3753 + "version": "2.6.3", 3754 + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", 3755 + "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", 3756 + "dependencies": { 3757 + "react-remove-scroll-bar": "^2.3.7", 3758 + "react-style-singleton": "^2.2.3", 3759 + "tslib": "^2.1.0", 3760 + "use-callback-ref": "^1.3.3", 3761 + "use-sidecar": "^1.1.3" 3762 + }, 3763 + "engines": { 3764 + "node": ">=10" 3765 + }, 3766 + "peerDependencies": { 3767 + "@types/react": "*", 3768 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" 3769 + }, 3770 + "peerDependenciesMeta": { 3771 + "@types/react": { 3772 + "optional": true 3773 + } 3774 + } 3775 + }, 3776 + "node_modules/react-remove-scroll-bar": { 3777 + "version": "2.3.8", 3778 + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", 3779 + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", 3780 + "dependencies": { 3781 + "react-style-singleton": "^2.2.2", 3782 + "tslib": "^2.0.0" 3783 + }, 3784 + "engines": { 3785 + "node": ">=10" 3786 + }, 3787 + "peerDependencies": { 3788 + "@types/react": "*", 3789 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" 3790 + }, 3791 + "peerDependenciesMeta": { 3792 + "@types/react": { 3793 + "optional": true 3794 + } 3795 + } 3796 + }, 3797 + "node_modules/react-style-singleton": { 3798 + "version": "2.2.3", 3799 + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", 3800 + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", 3801 + "dependencies": { 3802 + "get-nonce": "^1.0.0", 3803 + "tslib": "^2.0.0" 3804 + }, 3805 + "engines": { 3806 + "node": ">=10" 3807 + }, 3808 + "peerDependencies": { 3809 + "@types/react": "*", 3810 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" 3811 + }, 3812 + "peerDependenciesMeta": { 3813 + "@types/react": { 3814 + "optional": true 3815 + } 3816 + } 3817 + }, 3124 3818 "node_modules/read-cache": { 3125 3819 "version": "1.0.0", 3126 3820 "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", ··· 3637 4331 "dev": true, 3638 4332 "dependencies": { 3639 4333 "punycode": "^2.1.0" 4334 + } 4335 + }, 4336 + "node_modules/use-callback-ref": { 4337 + "version": "1.3.3", 4338 + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", 4339 + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", 4340 + "dependencies": { 4341 + "tslib": "^2.0.0" 4342 + }, 4343 + "engines": { 4344 + "node": ">=10" 4345 + }, 4346 + "peerDependencies": { 4347 + "@types/react": "*", 4348 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" 4349 + }, 4350 + "peerDependenciesMeta": { 4351 + "@types/react": { 4352 + "optional": true 4353 + } 4354 + } 4355 + }, 4356 + "node_modules/use-sidecar": { 4357 + "version": "1.1.3", 4358 + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", 4359 + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", 4360 + "dependencies": { 4361 + "detect-node-es": "^1.1.0", 4362 + "tslib": "^2.0.0" 4363 + }, 4364 + "engines": { 4365 + "node": ">=10" 4366 + }, 4367 + "peerDependencies": { 4368 + "@types/react": "*", 4369 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" 4370 + }, 4371 + "peerDependenciesMeta": { 4372 + "@types/react": { 4373 + "optional": true 4374 + } 3640 4375 } 3641 4376 }, 3642 4377 "node_modules/util-deprecate": {
+3 -1
mast-react-vite/package.json
··· 11 11 }, 12 12 "dependencies": { 13 13 "@radix-ui/react-checkbox": "^1.1.2", 14 + "@radix-ui/react-dialog": "^1.1.6", 14 15 "@radix-ui/react-icons": "^1.3.0", 15 16 "@radix-ui/react-scroll-area": "^1.2.3", 16 17 "@radix-ui/react-separator": "^1.1.2", 17 18 "@radix-ui/react-slot": "^1.1.2", 18 19 "@radix-ui/react-toggle": "^1.1.2", 19 20 "@radix-ui/react-toggle-group": "^1.1.2", 21 + "@radix-ui/react-tooltip": "^1.1.8", 20 22 "@tanstack/react-table": "^8.20.5", 21 23 "@vlcn.io/react": "^3.1.0", 22 24 "@vlcn.io/rx-tbl": "^0.15.0", 23 25 "@vlcn.io/ws-browserdb": "^0.2.0", 24 - "class-variance-authority": "^0.7.0", 26 + "class-variance-authority": "^0.7.1", 25 27 "clsx": "^2.1.1", 26 28 "lucide-react": "^0.454.0", 27 29 "react": "^18.3.1",
+45 -29
mast-react-vite/src/App.tsx
··· 1 - import { useState } from 'react' 1 + import { useState, useEffect } from 'react' 2 2 import { useQuery } from "@vlcn.io/react"; 3 3 import { 4 4 ColumnDef, 5 5 } from "@tanstack/react-table" 6 6 import { DataTable } from "@/components/ui/data-table" 7 - import * as commandParser from '@/lib/command_parser.js'; 7 + import * as commandParser from '@/lib/command_js.js'; 8 8 import { Checkbox } from "@/components/ui/checkbox" 9 - import { Input } from "@/components/ui/input" 9 + import { ActionParser } from "@/components/ui/action-parser" 10 + import { useSelection } from "@/contexts/selection-context" 11 + import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar" 12 + import { AppSidebar } from "@/components/ui/app-sidebar" 10 13 11 14 type Todo = { 12 15 id: string ··· 82 85 ] 83 86 84 87 function App({ ctx }) { 85 - const todos = useQuery(ctx, "SELECT * FROM todos where completed = 0").data; 86 88 const [newText, setNewText] = useState(""); 87 - const [rowSelection, setRowSelection] = useState({}); 88 89 // TODO: 89 90 // We need to seperate selection state 90 91 // From filter state ··· 92 93 // We want add to our selection state while we filter 93 94 // But selection state should apply to modify and done 94 95 // (but probably not add?) 95 - const [selectionContext, setSelectionContext] = useState({}); 96 + const { selectedItems } = useSelection(); 96 97 const [currentAction, setCurrentAction] = useState("add"); 97 98 99 + const todos = useQuery(ctx, `SELECT * FROM todos where completed = 0 100 + ${(currentAction === "filter") && (newText != "") ? "AND description LIKE ?" : ""}`, 101 + newText ? [`%${newText}%`] : []).data; 102 + console.log(todos[0]) 103 + 98 104 const handleActionChange = (action: string) => { 99 105 setCurrentAction(action); 106 + if (action === "done") { 107 + setNewText(selectedItems.size + " items selected") 108 + } else { 109 + setNewText("") 110 + } 100 111 }; 101 112 113 + useEffect(() => { 114 + if (currentAction === "done") { 115 + setNewText(selectedItems.size + " items selected") 116 + } 117 + }, [selectedItems]); 118 + 102 119 const executeCommand = (value: string) => { 103 120 try { 104 121 console.log(value) ··· 108 125 // Currently assumes that it is done 109 126 switch (parsed.type) { 110 127 case "done": 111 - if (parsed.filters && parsed.filters.length > 0) { 112 - const idFilters = parsed.filters.filter(f => f.type === "id"); 128 + // if (parsed.filters && parsed.filters.length > 0) { 129 + // const idFilters = parsed.filters.filter(f => f.type === "id"); 113 130 114 - // Get the row IDs from the table 115 - const rowIds = idFilters.flatMap(filter => 116 - filter.ids.map(id => todos[id - 1]?.id) 117 - ).filter(Boolean); 131 + // // Get the row IDs from the table 132 + // const rowIds = idFilters.flatMap(filter => 133 + // filter.ids.map(id => todos[id - 1]?.id) 134 + // ).filter(Boolean); 118 135 119 136 // Execute SQL update for each row 120 - if (rowIds.length > 0) { 121 - rowIds.forEach(id => { 137 + console.log("execute done: " + selectedItems) 138 + if (selectedItems.size > 0) { 139 + selectedItems.forEach(id => { 140 + console.log("clearing " + id) 122 141 ctx.db.exec( 123 142 `UPDATE todos SET completed = 1 WHERE id = ?`, 124 143 [id] ··· 126 145 }); 127 146 } 128 147 break; 129 - } 130 148 case "add": 131 149 ctx.db.exec(`INSERT INTO todos (id, description, tags, project, completed) 132 150 VALUES (lower(hex(randomblob(16))), ?, ?, ?, 0)`, ··· 138 156 break; 139 157 } 140 158 setNewText(""); 141 - setRowSelection({}); 142 159 } catch (error) { 143 160 // TODO: 144 161 // This is actually bad ··· 182 199 }) 183 200 }); 184 201 185 - setRowSelection(newSelection); 186 202 } 187 203 } catch (error) { 188 204 console.log("Unable to parse field onUpdate") 189 205 return; 190 206 } 191 207 } else { 192 - setRowSelection({}); 193 208 } 194 209 } 195 210 196 211 return ( 197 212 <> 198 - <div className="hidden md:flex flex-col w-full"> 199 - <section className="flex-1 container"> 200 - <Input type="text" 213 + <SidebarProvider defaultOpen={false} className="h-screen"> 214 + <div className="hidden md:flex flex-col w-full h-svh"> 215 + <AppSidebar/> 216 + <section className="flex-1 container py-12 h-[calc(100vh-theme(spacing.4))] overflow-hidden"> 217 + <SidebarTrigger className="fixed top-4 border"/> 218 + <ActionParser type="text" 201 219 className="bg-background" 202 220 value={newText} 203 221 onKeyUp={parseTodos} ··· 208 226 <div className="h-2" /> 209 227 <div className="flex-1 w-full"> 210 228 <DataTable 211 - columns={columns} 212 229 data={todos} 213 - rowSelection={rowSelection} 214 - setRowSelection={setRowSelection} 215 - setNewText={setNewText} 216 - newText={newText} 217 230 /> 218 231 </div> 219 232 </section> ··· 221 234 222 235 {/* Mobile view layout - shown only on mobile */} 223 236 <div className="md:hidden flex left-0 w-full h-full flex flex-col items-center pb-2"> 224 - <Input type="text" 237 + <AppSidebar/> 238 + <section className="flex-1 container py-12 h-[calc(100vh-theme(spacing.4))] overflow-hidden"> 239 + <SidebarTrigger className="fixed top-4 border"/> 240 + <ActionParser type="text" 225 241 className="bg-background" 226 242 value={newText} 227 243 onKeyUp={parseTodos} ··· 234 250 <DataTable 235 251 columns={columns} 236 252 data={todos} 237 - rowSelection={rowSelection} 238 - setRowSelection={setRowSelection} 239 253 setNewText={setNewText} 240 254 newText={newText} 241 255 /> 242 256 </div> 257 + </section> 243 258 </div> 259 + </SidebarProvider> 244 260 </> 245 261 ) 246 262 }
+171
mast-react-vite/src/components/ui/action-parser.tsx
··· 1 + import * as React from "react" 2 + 3 + import { cn } from "@/lib/utils" 4 + import { Button } from "@/components/ui/button" 5 + import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group" 6 + import { Search, Plus, Pencil, Check } from "lucide-react" 7 + 8 + // Add onActionChange to InputProps interface 9 + export interface InputProps 10 + extends React.InputHTMLAttributes<HTMLInputElement> { 11 + onActionChange?: (action: string) => void; 12 + onSubmit?: (value: string) => void; // Add this prop 13 + } 14 + 15 + const ActionParser = React.forwardRef<HTMLInputElement, InputProps>( 16 + ({ className, type, onActionChange, onSubmit, value, ...props }, ref) => { 17 + const [selectedIndex, setSelectedIndex] = React.useState(0) 18 + const [selectedToggle, setSelectedToggle] = React.useState("add") 19 + const options = ["add", "filter", "done", "delete"] 20 + 21 + const handleWheel = (event: React.WheelEvent) => { 22 + event.preventDefault() 23 + if (event.deltaY > 0) { 24 + const newIndex = (selectedIndex + 1) % options.length 25 + setSelectedIndex(newIndex) 26 + onActionChange?.(options[newIndex]) 27 + } else { 28 + const newIndex = (selectedIndex - 1 + options.length) % options.length 29 + setSelectedIndex(newIndex) 30 + onActionChange?.(options[newIndex]) 31 + } 32 + } 33 + 34 + 35 + const handleToggleChange = (value: string) => { 36 + if (value) { 37 + setSelectedToggle(value) 38 + onActionChange?.(value) 39 + } 40 + } 41 + 42 + const handleSubmit = () => { 43 + if (onSubmit && value) { 44 + console.log("trigger button") 45 + onSubmit(selectedToggle + " " + value); 46 + } 47 + } 48 + 49 + return ( 50 + <div className="flex flex-col group" onWheel={handleWheel}> 51 + <div className="hidden md:flex flex-col w-full"> 52 + <div className="flex w-full"> 53 + <div className="relative w-auto"> 54 + <ToggleGroup type="single" 55 + value={selectedToggle} 56 + onValueChange={handleToggleChange} 57 + defaultValue="add" 58 + className={cn( 59 + "h-11 border rounded-t-md border-b-0 bg-transparent text-sm cursor-default pt-1/2 pl-1 pr-1 pb-1/2", 60 + "shadow-sm transition-colors duration-0 text-center appearance-none group-focus-within:border-ring", 61 + "rounded-t-md rounded-b-none", 62 + "focus:border-ring focus-within:border-ring" 63 + )}> 64 + <ToggleGroupItem value="filter" aria-label="filter tasks"> 65 + <Search className="h-4 w-4 rounded-none" /> 66 + </ToggleGroupItem> 67 + <ToggleGroupItem value="modify" aria-label="Modify selected task(s)"> 68 + <Pencil className="h-4 w-4" /> 69 + </ToggleGroupItem> 70 + <ToggleGroupItem value="add" aria-label="Add a task"> 71 + <Plus className="h-4 w-4" /> 72 + </ToggleGroupItem> 73 + <ToggleGroupItem value="done" aria-label="Toggle selected task(s) done"> 74 + <Check className="h-4 w-4" /> 75 + </ToggleGroupItem> 76 + </ToggleGroup> 77 + <div className="absolute bottom-0 left-0 right-0 h-[2px] border group-focus-within:border-ring border-b-0 border-t-0 bg-background z-20 translate-y-[1px]"></div> 78 + </div> 79 + <div className="flex-1"></div> 80 + </div> 81 + <div className="relative w-full"> 82 + <input 83 + type={type} 84 + placeholder={selectedToggle} 85 + className={cn( 86 + "flex-1 h-9 w-full border rounded-r-md rounded-tl-none rounded-bl-md bg-background px-3 pr-12 text-base", 87 + "shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1", 88 + "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", 89 + "group-focus-within:border-ring", 90 + className 91 + )} 92 + ref={ref} 93 + value={value} 94 + {...props} 95 + /> 96 + <Button 97 + type="button" 98 + onClick={handleSubmit} 99 + className="absolute right-1 bottom-1 h-7 z-10" 100 + > 101 + 102 + </Button> 103 + </div> 104 + </div> 105 + 106 + {/* Mobile view layout - shown only on mobile */} 107 + <div className="md:hidden fixed bottom-0 left-0 w-full z-50 flex flex-col items-center pb-2"> 108 + <div className="relative w-auto"> 109 + <ToggleGroup type="single" 110 + value={selectedToggle} 111 + onValueChange={handleToggleChange} 112 + defaultValue="add" 113 + className={cn( 114 + "h-11 border rounded-t-md border-b-0 bg-background text-sm cursor-default pt-1/2 pl-1 pr-1 pb-1/2", 115 + "shadow-sm transition-colors duration-0 text-center appearance-none group-focus-within:border-ring", 116 + "rounded-t-md rounded-b-none", 117 + "focus:border-ring" 118 + )}> 119 + <ToggleGroupItem value="filter" aria-label="filter tasks" className="rounded-md mx-1 p-2"> 120 + <Search className="h-5 w-5" /> 121 + </ToggleGroupItem> 122 + <ToggleGroupItem value="modify" aria-label="Modify selected task(s)" className="rounded-md mx-1 p-2"> 123 + <Pencil className="h-5 w-5" /> 124 + </ToggleGroupItem> 125 + <ToggleGroupItem value="add" aria-label="Add a task" className="rounded-md mx-1 p-2"> 126 + <Plus className="h-5 w-5" /> 127 + </ToggleGroupItem> 128 + <ToggleGroupItem value="done" aria-label="Toggle selected task(s) done" className="rounded-md mx-1 p-2"> 129 + <Check className="h-5 w-5" /> 130 + </ToggleGroupItem> 131 + </ToggleGroup> 132 + <div className="absolute bottom-0 left-0 right-0 h-[2px] border border-b-0 border-t-0 group-focus-within:border-ring bg-background z-20 translate-y-[1px]"></div> 133 + </div> 134 + 135 + <div className="relative w-[90%] mb-1"> 136 + <input 137 + type={type} 138 + placeholder={selectedToggle} 139 + className={cn( 140 + "flex-1 h-9 w-full border bg-background px-3 pr-12 text-base", 141 + "shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1", 142 + "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", 143 + "group-focus-within:border-ring", 144 + // Modify border radius based on viewport size 145 + "md:rounded-r-md md:rounded-tl-none md:rounded-bl-md", 146 + "rounded-md", // For mobile view (full rounded corners) 147 + className 148 + 149 + )} 150 + ref={ref} 151 + value={value} 152 + {...props} 153 + /> 154 + <Button 155 + type="button" 156 + onClick={handleSubmit} 157 + className="absolute right-1 bottom-1 h-7 z-10" 158 + > 159 + 160 + </Button> 161 + </div> 162 + 163 + </div> 164 + </div > 165 + 166 + ) 167 + } 168 + ) 169 + ActionParser.displayName = "ActionParser" 170 + 171 + export { ActionParser }
+22
mast-react-vite/src/components/ui/app-sidebar.tsx
··· 1 + import { 2 + Sidebar, 3 + SidebarContent, 4 + SidebarFooter, 5 + SidebarGroup, 6 + SidebarHeader, 7 + } from "@/components/ui/sidebar" 8 + 9 + export function AppSidebar() { 10 + return ( 11 + <Sidebar> 12 + <SidebarHeader /> 13 + <SidebarContent> 14 + <SidebarGroup /> 15 + <SidebarGroup /> 16 + </SidebarContent> 17 + <SidebarFooter /> 18 + </Sidebar> 19 + ) 20 + } 21 + 22 +
+36
mast-react-vite/src/components/ui/badge.tsx
··· 1 + import * as React from "react" 2 + import { cva, type VariantProps } from "class-variance-authority" 3 + 4 + import { cn } from "@/lib/utils" 5 + 6 + const badgeVariants = cva( 7 + "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", 8 + { 9 + variants: { 10 + variant: { 11 + default: 12 + "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80", 13 + secondary: 14 + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", 15 + destructive: 16 + "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80", 17 + outline: "text-foreground", 18 + }, 19 + }, 20 + defaultVariants: { 21 + variant: "default", 22 + }, 23 + } 24 + ) 25 + 26 + export interface BadgeProps 27 + extends React.HTMLAttributes<HTMLDivElement>, 28 + VariantProps<typeof badgeVariants> {} 29 + 30 + function Badge({ className, variant, ...props }: BadgeProps) { 31 + return ( 32 + <div className={cn(badgeVariants({ variant }), className)} {...props} /> 33 + ) 34 + } 35 + 36 + export { Badge, badgeVariants }
+17 -63
mast-react-vite/src/components/ui/data-table.tsx
··· 5 5 import { Task } from "@/components/ui/task" 6 6 7 7 import { 8 - ColumnDef, 9 8 ColumnSizingState, 10 - RowSelectionState, 11 - flexRender, 12 9 getCoreRowModel, 13 10 useReactTable, 14 11 } from "@tanstack/react-table" 15 12 16 - import { 17 - Table, 18 - TableBody, 19 - TableCell, 20 - TableHead, 21 - TableHeader, 22 - TableRow, 23 - } from "@/components/ui/table" 24 - 25 - interface DataTableProps<TData, TValue> { 26 - columns: ColumnDef<TData, TValue>[] 13 + interface DataTableProps<TData> { 27 14 data: TData[] 28 - rowSelection: {} 29 - setRowSelection: (value: {}) => void 30 15 } 31 16 32 - export function DataTable<TData, TValue>({ 33 - columns, 34 - data, 35 - rowSelection, 36 - setNewText, 37 - newText, 38 - setRowSelection, 39 - }: DataTableProps<TData, TValue>) { 40 - const [colSizing, setColSizing] = useState<ColumnSizingState>({}); 41 - const table = useReactTable({ 42 - data, 43 - columns, 44 - enableColumnResizing: true, 45 - columnResizeMode: "onChange", 46 - getCoreRowModel: getCoreRowModel(), 47 - onColumnSizingChange: setColSizing, 48 - onRowSelectionChange: setRowSelection, 49 - state: { 50 - columnSizing: colSizing, 51 - rowSelection: rowSelection, 52 - }, 53 - meta: { 54 - setNewText, 55 - newText, 56 - } 57 - }) 17 + export function DataTable<TData>({ data, }: DataTableProps<TData>) { 58 18 59 19 return ( 60 20 61 21 <> 62 22 <div className="hidden md:flex flex-col w-full"> 63 23 <ScrollArea className="h-[calc(100vh-12rem)] rounded-md border"> 64 - {table.getRowModel().rows?.length ? ( 65 - table.getRowModel().rows.map((row) => ( 66 - <Task 67 - key={row.id} 68 - selected={row.getIsSelected()} 69 - onSelect={() => row.toggleSelected()} 70 - data={row.original} 71 - /> 72 - )) 73 - ) : ( 74 - <div className="text-center py-4 text-muted-foreground"> 75 - No results. 76 - </div> 77 - )} 78 - </ScrollArea> 24 + {data.length ? ( 25 + data.map((item) => ( 26 + <Task 27 + data={item} 28 + /> 29 + )) 30 + ) : ( 31 + <div className="text-center py-4 text-muted-foreground"> 32 + No results. 33 + </div> 34 + )} 35 + </ScrollArea> 79 36 </div> 80 37 81 38 {/* Mobile view layout - shown only on mobile */} 82 39 <div className="md:hidden"> 83 40 <ScrollArea className="h-[calc(100vh)] rounded-md border"> 84 - {table.getRowModel().rows?.length ? ( 85 - table.getRowModel().rows.map((row) => ( 41 + {data.length ? ( 42 + data.map((item) => ( 86 43 <Task 87 - key={row.id} 88 - selected={row.getIsSelected()} 89 - onSelect={() => row.toggleSelected()} 90 - data={row.original} 44 + data={item} 91 45 /> 92 46 )) 93 47 ) : (
+11 -160
mast-react-vite/src/components/ui/input.tsx
··· 1 1 import * as React from "react" 2 2 3 3 import { cn } from "@/lib/utils" 4 - import { Button } from "@/components/ui/button" 5 - import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group" 6 - import { Search, Plus, Pencil, Check } from "lucide-react" 7 4 8 - // Add onActionChange to InputProps interface 9 - export interface InputProps 10 - extends React.InputHTMLAttributes<HTMLInputElement> { 11 - onActionChange?: (action: string) => void; 12 - onSubmit?: (value: string) => void; // Add this prop 13 - } 14 - 15 - const Input = React.forwardRef<HTMLInputElement, InputProps>( 16 - ({ className, type, onActionChange, onSubmit, value, ...props }, ref) => { 17 - const [selectedIndex, setSelectedIndex] = React.useState(0) 18 - const [selectedToggle, setSelectedToggle] = React.useState("add") 19 - const options = ["add", "filter", "done", "delete"] 20 - 21 - const handleWheel = (event: React.WheelEvent) => { 22 - event.preventDefault() 23 - if (event.deltaY > 0) { 24 - const newIndex = (selectedIndex + 1) % options.length 25 - setSelectedIndex(newIndex) 26 - onActionChange?.(options[newIndex]) 27 - } else { 28 - const newIndex = (selectedIndex - 1 + options.length) % options.length 29 - setSelectedIndex(newIndex) 30 - onActionChange?.(options[newIndex]) 31 - } 32 - } 33 - 34 - 35 - const handleToggleChange = (value: string) => { 36 - if (value) { 37 - setSelectedToggle(value) 38 - onActionChange?.(value) 39 - } 40 - } 41 - 42 - const handleSubmit = () => { 43 - if (onSubmit && value) { 44 - console.log("trigger button") 45 - onSubmit(selectedToggle + " " + value); 46 - } 47 - } 48 - 5 + const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>( 6 + ({ className, type, ...props }, ref) => { 49 7 return ( 50 - <div className="flex flex-col group" onWheel={handleWheel}> 51 - <div className="hidden md:flex flex-col w-full"> 52 - <div className="flex w-full"> 53 - <div className="relative w-auto"> 54 - <ToggleGroup type="single" 55 - value={selectedToggle} 56 - onValueChange={handleToggleChange} 57 - defaultValue="add" 58 - className={cn( 59 - "h-11 border rounded-t-md border-b-0 bg-transparent text-sm cursor-default pt-1/2 pl-1 pr-1 pb-1/2", 60 - "shadow-sm transition-colors duration-0 text-center appearance-none group-focus-within:border-ring", 61 - "rounded-t-md rounded-b-none", 62 - "focus:border-ring focus-within:border-ring" 63 - )}> 64 - <ToggleGroupItem value="filter" aria-label="filter tasks"> 65 - <Search className="h-4 w-4 rounded-none" /> 66 - </ToggleGroupItem> 67 - <ToggleGroupItem value="modify" aria-label="Modify selected task(s)"> 68 - <Pencil className="h-4 w-4" /> 69 - </ToggleGroupItem> 70 - <ToggleGroupItem value="add" aria-label="Add a task"> 71 - <Plus className="h-4 w-4" /> 72 - </ToggleGroupItem> 73 - <ToggleGroupItem value="done" aria-label="Toggle selected task(s) done"> 74 - <Check className="h-4 w-4" /> 75 - </ToggleGroupItem> 76 - </ToggleGroup> 77 - <div className="absolute bottom-0 left-0 right-0 h-[2px] border group-focus-within:border-ring border-b-0 border-t-0 bg-background z-20 translate-y-[1px]"></div> 78 - </div> 79 - <div className="flex-1"></div> 80 - </div> 81 - <div className="relative w-full"> 82 - <input 83 - type={type} 84 - placeholder={selectedToggle} 85 - className={cn( 86 - "flex-1 h-9 w-full border rounded-r-md rounded-tl-none rounded-bl-md bg-background px-3 pr-12 text-base", 87 - "shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1", 88 - "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", 89 - "group-focus-within:border-ring", 90 - className 91 - )} 92 - ref={ref} 93 - value={value} 94 - {...props} 95 - /> 96 - <Button 97 - type="button" 98 - onClick={handleSubmit} 99 - className="absolute right-1 bottom-1 h-7 z-10" 100 - > 101 - 102 - </Button> 103 - </div> 104 - </div> 105 - 106 - {/* Mobile view layout - shown only on mobile */} 107 - <div className="md:hidden fixed bottom-0 left-0 w-full z-50 flex flex-col items-center pb-2"> 108 - <div className="relative w-auto"> 109 - <ToggleGroup type="single" 110 - value={selectedToggle} 111 - onValueChange={handleToggleChange} 112 - defaultValue="add" 113 - className={cn( 114 - "h-11 border rounded-t-md border-b-0 bg-background text-sm cursor-default pt-1/2 pl-1 pr-1 pb-1/2", 115 - "shadow-sm transition-colors duration-0 text-center appearance-none group-focus-within:border-ring", 116 - "rounded-t-md rounded-b-none", 117 - "focus:border-ring" 118 - )}> 119 - <ToggleGroupItem value="filter" aria-label="filter tasks" className="rounded-md mx-1 p-2"> 120 - <Search className="h-5 w-5" /> 121 - </ToggleGroupItem> 122 - <ToggleGroupItem value="modify" aria-label="Modify selected task(s)" className="rounded-md mx-1 p-2"> 123 - <Pencil className="h-5 w-5" /> 124 - </ToggleGroupItem> 125 - <ToggleGroupItem value="add" aria-label="Add a task" className="rounded-md mx-1 p-2"> 126 - <Plus className="h-5 w-5" /> 127 - </ToggleGroupItem> 128 - <ToggleGroupItem value="done" aria-label="Toggle selected task(s) done" className="rounded-md mx-1 p-2"> 129 - <Check className="h-5 w-5" /> 130 - </ToggleGroupItem> 131 - </ToggleGroup> 132 - <div className="absolute bottom-0 left-0 right-0 h-[2px] border border-b-0 border-t-0 group-focus-within:border-ring bg-background z-20 translate-y-[1px]"></div> 133 - </div> 134 - 135 - <div className="relative w-[90%] mb-1"> 136 - <input 137 - type={type} 138 - placeholder={selectedToggle} 139 - className={cn( 140 - "flex-1 h-9 w-full border bg-background px-3 pr-12 text-base", 141 - "shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1", 142 - "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", 143 - "group-focus-within:border-ring", 144 - // Modify border radius based on viewport size 145 - "md:rounded-r-md md:rounded-tl-none md:rounded-bl-md", 146 - "rounded-md", // For mobile view (full rounded corners) 147 - className 148 - 149 - )} 150 - ref={ref} 151 - value={value} 152 - {...props} 153 - /> 154 - <Button 155 - type="button" 156 - onClick={handleSubmit} 157 - className="absolute right-1 bottom-1 h-7 z-10" 158 - > 159 - 160 - </Button> 161 - </div> 162 - 163 - </div> 164 - </div > 165 - 8 + <input 9 + type={type} 10 + className={cn( 11 + "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", 12 + className 13 + )} 14 + ref={ref} 15 + {...props} 16 + /> 166 17 ) 167 18 } 168 19 )
+139
mast-react-vite/src/components/ui/sheet.tsx
··· 1 + "use client" 2 + 3 + import * as React from "react" 4 + import * as SheetPrimitive from "@radix-ui/react-dialog" 5 + import { cva, type VariantProps } from "class-variance-authority" 6 + import { cn } from "@/lib/utils" 7 + import { Cross2Icon } from "@radix-ui/react-icons" 8 + 9 + const Sheet = SheetPrimitive.Root 10 + 11 + const SheetTrigger = SheetPrimitive.Trigger 12 + 13 + const SheetClose = SheetPrimitive.Close 14 + 15 + const SheetPortal = SheetPrimitive.Portal 16 + 17 + const SheetOverlay = React.forwardRef< 18 + React.ElementRef<typeof SheetPrimitive.Overlay>, 19 + React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay> 20 + >(({ className, ...props }, ref) => ( 21 + <SheetPrimitive.Overlay 22 + className={cn( 23 + "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", 24 + className 25 + )} 26 + {...props} 27 + ref={ref} 28 + /> 29 + )) 30 + SheetOverlay.displayName = SheetPrimitive.Overlay.displayName 31 + 32 + const sheetVariants = cva( 33 + "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out", 34 + { 35 + variants: { 36 + side: { 37 + top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", 38 + bottom: 39 + "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", 40 + left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", 41 + right: 42 + "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", 43 + }, 44 + }, 45 + defaultVariants: { 46 + side: "right", 47 + }, 48 + } 49 + ) 50 + 51 + interface SheetContentProps 52 + extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, 53 + VariantProps<typeof sheetVariants> {} 54 + 55 + const SheetContent = React.forwardRef< 56 + React.ElementRef<typeof SheetPrimitive.Content>, 57 + SheetContentProps 58 + >(({ side = "right", className, children, ...props }, ref) => ( 59 + <SheetPortal> 60 + <SheetOverlay /> 61 + <SheetPrimitive.Content 62 + ref={ref} 63 + className={cn(sheetVariants({ side }), className)} 64 + {...props} 65 + > 66 + <SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"> 67 + <Cross2Icon className="h-4 w-4" /> 68 + <span className="sr-only">Close</span> 69 + </SheetPrimitive.Close> 70 + {children} 71 + </SheetPrimitive.Content> 72 + </SheetPortal> 73 + )) 74 + SheetContent.displayName = SheetPrimitive.Content.displayName 75 + 76 + const SheetHeader = ({ 77 + className, 78 + ...props 79 + }: React.HTMLAttributes<HTMLDivElement>) => ( 80 + <div 81 + className={cn( 82 + "flex flex-col space-y-2 text-center sm:text-left", 83 + className 84 + )} 85 + {...props} 86 + /> 87 + ) 88 + SheetHeader.displayName = "SheetHeader" 89 + 90 + const SheetFooter = ({ 91 + className, 92 + ...props 93 + }: React.HTMLAttributes<HTMLDivElement>) => ( 94 + <div 95 + className={cn( 96 + "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", 97 + className 98 + )} 99 + {...props} 100 + /> 101 + ) 102 + SheetFooter.displayName = "SheetFooter" 103 + 104 + const SheetTitle = React.forwardRef< 105 + React.ElementRef<typeof SheetPrimitive.Title>, 106 + React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title> 107 + >(({ className, ...props }, ref) => ( 108 + <SheetPrimitive.Title 109 + ref={ref} 110 + className={cn("text-lg font-semibold text-foreground", className)} 111 + {...props} 112 + /> 113 + )) 114 + SheetTitle.displayName = SheetPrimitive.Title.displayName 115 + 116 + const SheetDescription = React.forwardRef< 117 + React.ElementRef<typeof SheetPrimitive.Description>, 118 + React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description> 119 + >(({ className, ...props }, ref) => ( 120 + <SheetPrimitive.Description 121 + ref={ref} 122 + className={cn("text-sm text-muted-foreground", className)} 123 + {...props} 124 + /> 125 + )) 126 + SheetDescription.displayName = SheetPrimitive.Description.displayName 127 + 128 + export { 129 + Sheet, 130 + SheetPortal, 131 + SheetOverlay, 132 + SheetTrigger, 133 + SheetClose, 134 + SheetContent, 135 + SheetHeader, 136 + SheetFooter, 137 + SheetTitle, 138 + SheetDescription, 139 + }
+770
mast-react-vite/src/components/ui/sidebar.tsx
··· 1 + import * as React from "react" 2 + import { Slot } from "@radix-ui/react-slot" 3 + import { VariantProps, cva } from "class-variance-authority" 4 + import { useIsMobile } from "@/hooks/use-mobile" 5 + import { cn } from "@/lib/utils" 6 + import { Button } from "@/components/ui/button" 7 + import { Input } from "@/components/ui/input" 8 + import { Separator } from "@/components/ui/separator" 9 + import { 10 + Sheet, 11 + SheetContent, 12 + SheetDescription, 13 + SheetHeader, 14 + SheetTitle, 15 + } from "@/components/ui/sheet" 16 + import { Skeleton } from "@/components/ui/skeleton" 17 + import { 18 + Tooltip, 19 + TooltipContent, 20 + TooltipProvider, 21 + TooltipTrigger, 22 + } from "@/components/ui/tooltip" 23 + import { ViewVerticalIcon } from "@radix-ui/react-icons" 24 + 25 + const SIDEBAR_COOKIE_NAME = "sidebar_state" 26 + const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7 27 + const SIDEBAR_WIDTH = "16rem" 28 + const SIDEBAR_WIDTH_MOBILE = "18rem" 29 + const SIDEBAR_WIDTH_ICON = "3rem" 30 + const SIDEBAR_KEYBOARD_SHORTCUT = "b" 31 + 32 + type SidebarContext = { 33 + state: "expanded" | "collapsed" 34 + open: boolean 35 + setOpen: (open: boolean) => void 36 + openMobile: boolean 37 + setOpenMobile: (open: boolean) => void 38 + isMobile: boolean 39 + toggleSidebar: () => void 40 + } 41 + 42 + const SidebarContext = React.createContext<SidebarContext | null>(null) 43 + 44 + function useSidebar() { 45 + const context = React.useContext(SidebarContext) 46 + if (!context) { 47 + throw new Error("useSidebar must be used within a SidebarProvider.") 48 + } 49 + 50 + return context 51 + } 52 + 53 + const SidebarProvider = React.forwardRef< 54 + HTMLDivElement, 55 + React.ComponentProps<"div"> & { 56 + defaultOpen?: boolean 57 + open?: boolean 58 + onOpenChange?: (open: boolean) => void 59 + } 60 + >( 61 + ( 62 + { 63 + defaultOpen = true, 64 + open: openProp, 65 + onOpenChange: setOpenProp, 66 + className, 67 + style, 68 + children, 69 + ...props 70 + }, 71 + ref 72 + ) => { 73 + const isMobile = useIsMobile() 74 + const [openMobile, setOpenMobile] = React.useState(false) 75 + 76 + // This is the internal state of the sidebar. 77 + // We use openProp and setOpenProp for control from outside the component. 78 + const [_open, _setOpen] = React.useState(defaultOpen) 79 + const open = openProp ?? _open 80 + const setOpen = React.useCallback( 81 + (value: boolean | ((value: boolean) => boolean)) => { 82 + const openState = typeof value === "function" ? value(open) : value 83 + if (setOpenProp) { 84 + setOpenProp(openState) 85 + } else { 86 + _setOpen(openState) 87 + } 88 + 89 + // This sets the cookie to keep the sidebar state. 90 + document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}` 91 + }, 92 + [setOpenProp, open] 93 + ) 94 + 95 + // Helper to toggle the sidebar. 96 + const toggleSidebar = React.useCallback(() => { 97 + return isMobile 98 + ? setOpenMobile((open) => !open) 99 + : setOpen((open) => !open) 100 + }, [isMobile, setOpen, setOpenMobile]) 101 + 102 + // Adds a keyboard shortcut to toggle the sidebar. 103 + React.useEffect(() => { 104 + const handleKeyDown = (event: KeyboardEvent) => { 105 + if ( 106 + event.key === SIDEBAR_KEYBOARD_SHORTCUT && 107 + (event.metaKey || event.ctrlKey) 108 + ) { 109 + event.preventDefault() 110 + toggleSidebar() 111 + } 112 + } 113 + 114 + window.addEventListener("keydown", handleKeyDown) 115 + return () => window.removeEventListener("keydown", handleKeyDown) 116 + }, [toggleSidebar]) 117 + 118 + // We add a state so that we can do data-state="expanded" or "collapsed". 119 + // This makes it easier to style the sidebar with Tailwind classes. 120 + const state = open ? "expanded" : "collapsed" 121 + 122 + const contextValue = React.useMemo<SidebarContext>( 123 + () => ({ 124 + state, 125 + open, 126 + setOpen, 127 + isMobile, 128 + openMobile, 129 + setOpenMobile, 130 + toggleSidebar, 131 + }), 132 + [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar] 133 + ) 134 + 135 + return ( 136 + <SidebarContext.Provider value={contextValue}> 137 + <TooltipProvider delayDuration={0}> 138 + <div 139 + style={ 140 + { 141 + "--sidebar-width": SIDEBAR_WIDTH, 142 + "--sidebar-width-icon": SIDEBAR_WIDTH_ICON, 143 + ...style, 144 + } as React.CSSProperties 145 + } 146 + className={cn( 147 + "group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar", 148 + className 149 + )} 150 + ref={ref} 151 + {...props} 152 + > 153 + {children} 154 + </div> 155 + </TooltipProvider> 156 + </SidebarContext.Provider> 157 + ) 158 + } 159 + ) 160 + SidebarProvider.displayName = "SidebarProvider" 161 + 162 + const Sidebar = React.forwardRef< 163 + HTMLDivElement, 164 + React.ComponentProps<"div"> & { 165 + side?: "left" | "right" 166 + variant?: "sidebar" | "floating" | "inset" 167 + collapsible?: "offcanvas" | "icon" | "none" 168 + } 169 + >( 170 + ( 171 + { 172 + side = "left", 173 + variant = "sidebar", 174 + collapsible = "offcanvas", 175 + className, 176 + children, 177 + ...props 178 + }, 179 + ref 180 + ) => { 181 + const { isMobile, state, openMobile, setOpenMobile } = useSidebar() 182 + 183 + if (collapsible === "none") { 184 + return ( 185 + <div 186 + className={cn( 187 + "flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground", 188 + className 189 + )} 190 + ref={ref} 191 + {...props} 192 + > 193 + {children} 194 + </div> 195 + ) 196 + } 197 + 198 + if (isMobile) { 199 + return ( 200 + <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}> 201 + <SheetContent 202 + data-sidebar="sidebar" 203 + data-mobile="true" 204 + className="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden" 205 + style={ 206 + { 207 + "--sidebar-width": SIDEBAR_WIDTH_MOBILE, 208 + } as React.CSSProperties 209 + } 210 + side={side} 211 + > 212 + <SheetHeader className="sr-only"> 213 + <SheetTitle>Sidebar</SheetTitle> 214 + <SheetDescription>Displays the mobile sidebar.</SheetDescription> 215 + </SheetHeader> 216 + <div className="flex h-full w-full flex-col">{children}</div> 217 + </SheetContent> 218 + </Sheet> 219 + ) 220 + } 221 + 222 + return ( 223 + <div 224 + ref={ref} 225 + className="group peer hidden text-sidebar-foreground md:block" 226 + data-state={state} 227 + data-collapsible={state === "collapsed" ? collapsible : ""} 228 + data-variant={variant} 229 + data-side={side} 230 + > 231 + {/* This is what handles the sidebar gap on desktop */} 232 + <div 233 + className={cn( 234 + "relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear", 235 + "group-data-[collapsible=offcanvas]:w-0", 236 + "group-data-[side=right]:rotate-180", 237 + variant === "floating" || variant === "inset" 238 + ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" 239 + : "group-data-[collapsible=icon]:w-[--sidebar-width-icon]" 240 + )} 241 + /> 242 + <div 243 + className={cn( 244 + "fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex", 245 + side === "left" 246 + ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" 247 + : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]", 248 + // Adjust the padding for floating and inset variants. 249 + variant === "floating" || variant === "inset" 250 + ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" 251 + : "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l", 252 + className 253 + )} 254 + {...props} 255 + > 256 + <div 257 + data-sidebar="sidebar" 258 + className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow" 259 + > 260 + {children} 261 + </div> 262 + </div> 263 + </div> 264 + ) 265 + } 266 + ) 267 + Sidebar.displayName = "Sidebar" 268 + 269 + const SidebarTrigger = React.forwardRef< 270 + React.ElementRef<typeof Button>, 271 + React.ComponentProps<typeof Button> 272 + >(({ className, onClick, ...props }, ref) => { 273 + const { toggleSidebar } = useSidebar() 274 + 275 + return ( 276 + <Button 277 + ref={ref} 278 + data-sidebar="trigger" 279 + variant="ghost" 280 + size="icon" 281 + className={cn("h-7 w-7", className)} 282 + onClick={(event) => { 283 + onClick?.(event) 284 + toggleSidebar() 285 + }} 286 + {...props} 287 + > 288 + <ViewVerticalIcon /> 289 + <span className="sr-only">Toggle Sidebar</span> 290 + </Button> 291 + ) 292 + }) 293 + SidebarTrigger.displayName = "SidebarTrigger" 294 + 295 + const SidebarRail = React.forwardRef< 296 + HTMLButtonElement, 297 + React.ComponentProps<"button"> 298 + >(({ className, ...props }, ref) => { 299 + const { toggleSidebar } = useSidebar() 300 + 301 + return ( 302 + <button 303 + ref={ref} 304 + data-sidebar="rail" 305 + aria-label="Toggle Sidebar" 306 + tabIndex={-1} 307 + onClick={toggleSidebar} 308 + title="Toggle Sidebar" 309 + className={cn( 310 + "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex", 311 + "[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize", 312 + "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize", 313 + "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar", 314 + "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", 315 + "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", 316 + className 317 + )} 318 + {...props} 319 + /> 320 + ) 321 + }) 322 + SidebarRail.displayName = "SidebarRail" 323 + 324 + const SidebarInset = React.forwardRef< 325 + HTMLDivElement, 326 + React.ComponentProps<"main"> 327 + >(({ className, ...props }, ref) => { 328 + return ( 329 + <main 330 + ref={ref} 331 + className={cn( 332 + "relative flex w-full flex-1 flex-col bg-background", 333 + "md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow", 334 + className 335 + )} 336 + {...props} 337 + /> 338 + ) 339 + }) 340 + SidebarInset.displayName = "SidebarInset" 341 + 342 + const SidebarInput = React.forwardRef< 343 + React.ElementRef<typeof Input>, 344 + React.ComponentProps<typeof Input> 345 + >(({ className, ...props }, ref) => { 346 + return ( 347 + <Input 348 + ref={ref} 349 + data-sidebar="input" 350 + className={cn( 351 + "h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring", 352 + className 353 + )} 354 + {...props} 355 + /> 356 + ) 357 + }) 358 + SidebarInput.displayName = "SidebarInput" 359 + 360 + const SidebarHeader = React.forwardRef< 361 + HTMLDivElement, 362 + React.ComponentProps<"div"> 363 + >(({ className, ...props }, ref) => { 364 + return ( 365 + <div 366 + ref={ref} 367 + data-sidebar="header" 368 + className={cn("flex flex-col gap-2 p-2", className)} 369 + {...props} 370 + /> 371 + ) 372 + }) 373 + SidebarHeader.displayName = "SidebarHeader" 374 + 375 + const SidebarFooter = React.forwardRef< 376 + HTMLDivElement, 377 + React.ComponentProps<"div"> 378 + >(({ className, ...props }, ref) => { 379 + return ( 380 + <div 381 + ref={ref} 382 + data-sidebar="footer" 383 + className={cn("flex flex-col gap-2 p-2", className)} 384 + {...props} 385 + /> 386 + ) 387 + }) 388 + SidebarFooter.displayName = "SidebarFooter" 389 + 390 + const SidebarSeparator = React.forwardRef< 391 + React.ElementRef<typeof Separator>, 392 + React.ComponentProps<typeof Separator> 393 + >(({ className, ...props }, ref) => { 394 + return ( 395 + <Separator 396 + ref={ref} 397 + data-sidebar="separator" 398 + className={cn("mx-2 w-auto bg-sidebar-border", className)} 399 + {...props} 400 + /> 401 + ) 402 + }) 403 + SidebarSeparator.displayName = "SidebarSeparator" 404 + 405 + const SidebarContent = React.forwardRef< 406 + HTMLDivElement, 407 + React.ComponentProps<"div"> 408 + >(({ className, ...props }, ref) => { 409 + return ( 410 + <div 411 + ref={ref} 412 + data-sidebar="content" 413 + className={cn( 414 + "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden", 415 + className 416 + )} 417 + {...props} 418 + /> 419 + ) 420 + }) 421 + SidebarContent.displayName = "SidebarContent" 422 + 423 + const SidebarGroup = React.forwardRef< 424 + HTMLDivElement, 425 + React.ComponentProps<"div"> 426 + >(({ className, ...props }, ref) => { 427 + return ( 428 + <div 429 + ref={ref} 430 + data-sidebar="group" 431 + className={cn("relative flex w-full min-w-0 flex-col p-2", className)} 432 + {...props} 433 + /> 434 + ) 435 + }) 436 + SidebarGroup.displayName = "SidebarGroup" 437 + 438 + const SidebarGroupLabel = React.forwardRef< 439 + HTMLDivElement, 440 + React.ComponentProps<"div"> & { asChild?: boolean } 441 + >(({ className, asChild = false, ...props }, ref) => { 442 + const Comp = asChild ? Slot : "div" 443 + 444 + return ( 445 + <Comp 446 + ref={ref} 447 + data-sidebar="group-label" 448 + className={cn( 449 + "flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", 450 + "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0", 451 + className 452 + )} 453 + {...props} 454 + /> 455 + ) 456 + }) 457 + SidebarGroupLabel.displayName = "SidebarGroupLabel" 458 + 459 + const SidebarGroupAction = React.forwardRef< 460 + HTMLButtonElement, 461 + React.ComponentProps<"button"> & { asChild?: boolean } 462 + >(({ className, asChild = false, ...props }, ref) => { 463 + const Comp = asChild ? Slot : "button" 464 + 465 + return ( 466 + <Comp 467 + ref={ref} 468 + data-sidebar="group-action" 469 + className={cn( 470 + "absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", 471 + // Increases the hit area of the button on mobile. 472 + "after:absolute after:-inset-2 after:md:hidden", 473 + "group-data-[collapsible=icon]:hidden", 474 + className 475 + )} 476 + {...props} 477 + /> 478 + ) 479 + }) 480 + SidebarGroupAction.displayName = "SidebarGroupAction" 481 + 482 + const SidebarGroupContent = React.forwardRef< 483 + HTMLDivElement, 484 + React.ComponentProps<"div"> 485 + >(({ className, ...props }, ref) => ( 486 + <div 487 + ref={ref} 488 + data-sidebar="group-content" 489 + className={cn("w-full text-sm", className)} 490 + {...props} 491 + /> 492 + )) 493 + SidebarGroupContent.displayName = "SidebarGroupContent" 494 + 495 + const SidebarMenu = React.forwardRef< 496 + HTMLUListElement, 497 + React.ComponentProps<"ul"> 498 + >(({ className, ...props }, ref) => ( 499 + <ul 500 + ref={ref} 501 + data-sidebar="menu" 502 + className={cn("flex w-full min-w-0 flex-col gap-1", className)} 503 + {...props} 504 + /> 505 + )) 506 + SidebarMenu.displayName = "SidebarMenu" 507 + 508 + const SidebarMenuItem = React.forwardRef< 509 + HTMLLIElement, 510 + React.ComponentProps<"li"> 511 + >(({ className, ...props }, ref) => ( 512 + <li 513 + ref={ref} 514 + data-sidebar="menu-item" 515 + className={cn("group/menu-item relative", className)} 516 + {...props} 517 + /> 518 + )) 519 + SidebarMenuItem.displayName = "SidebarMenuItem" 520 + 521 + const sidebarMenuButtonVariants = cva( 522 + "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", 523 + { 524 + variants: { 525 + variant: { 526 + default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", 527 + outline: 528 + "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]", 529 + }, 530 + size: { 531 + default: "h-8 text-sm", 532 + sm: "h-7 text-xs", 533 + lg: "h-12 text-sm group-data-[collapsible=icon]:!p-0", 534 + }, 535 + }, 536 + defaultVariants: { 537 + variant: "default", 538 + size: "default", 539 + }, 540 + } 541 + ) 542 + 543 + const SidebarMenuButton = React.forwardRef< 544 + HTMLButtonElement, 545 + React.ComponentProps<"button"> & { 546 + asChild?: boolean 547 + isActive?: boolean 548 + tooltip?: string | React.ComponentProps<typeof TooltipContent> 549 + } & VariantProps<typeof sidebarMenuButtonVariants> 550 + >( 551 + ( 552 + { 553 + asChild = false, 554 + isActive = false, 555 + variant = "default", 556 + size = "default", 557 + tooltip, 558 + className, 559 + ...props 560 + }, 561 + ref 562 + ) => { 563 + const Comp = asChild ? Slot : "button" 564 + const { isMobile, state } = useSidebar() 565 + 566 + const button = ( 567 + <Comp 568 + ref={ref} 569 + data-sidebar="menu-button" 570 + data-size={size} 571 + data-active={isActive} 572 + className={cn(sidebarMenuButtonVariants({ variant, size }), className)} 573 + {...props} 574 + /> 575 + ) 576 + 577 + if (!tooltip) { 578 + return button 579 + } 580 + 581 + if (typeof tooltip === "string") { 582 + tooltip = { 583 + children: tooltip, 584 + } 585 + } 586 + 587 + return ( 588 + <Tooltip> 589 + <TooltipTrigger asChild>{button}</TooltipTrigger> 590 + <TooltipContent 591 + side="right" 592 + align="center" 593 + hidden={state !== "collapsed" || isMobile} 594 + {...tooltip} 595 + /> 596 + </Tooltip> 597 + ) 598 + } 599 + ) 600 + SidebarMenuButton.displayName = "SidebarMenuButton" 601 + 602 + const SidebarMenuAction = React.forwardRef< 603 + HTMLButtonElement, 604 + React.ComponentProps<"button"> & { 605 + asChild?: boolean 606 + showOnHover?: boolean 607 + } 608 + >(({ className, asChild = false, showOnHover = false, ...props }, ref) => { 609 + const Comp = asChild ? Slot : "button" 610 + 611 + return ( 612 + <Comp 613 + ref={ref} 614 + data-sidebar="menu-action" 615 + className={cn( 616 + "absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0", 617 + // Increases the hit area of the button on mobile. 618 + "after:absolute after:-inset-2 after:md:hidden", 619 + "peer-data-[size=sm]/menu-button:top-1", 620 + "peer-data-[size=default]/menu-button:top-1.5", 621 + "peer-data-[size=lg]/menu-button:top-2.5", 622 + "group-data-[collapsible=icon]:hidden", 623 + showOnHover && 624 + "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0", 625 + className 626 + )} 627 + {...props} 628 + /> 629 + ) 630 + }) 631 + SidebarMenuAction.displayName = "SidebarMenuAction" 632 + 633 + const SidebarMenuBadge = React.forwardRef< 634 + HTMLDivElement, 635 + React.ComponentProps<"div"> 636 + >(({ className, ...props }, ref) => ( 637 + <div 638 + ref={ref} 639 + data-sidebar="menu-badge" 640 + className={cn( 641 + "pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums text-sidebar-foreground", 642 + "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground", 643 + "peer-data-[size=sm]/menu-button:top-1", 644 + "peer-data-[size=default]/menu-button:top-1.5", 645 + "peer-data-[size=lg]/menu-button:top-2.5", 646 + "group-data-[collapsible=icon]:hidden", 647 + className 648 + )} 649 + {...props} 650 + /> 651 + )) 652 + SidebarMenuBadge.displayName = "SidebarMenuBadge" 653 + 654 + const SidebarMenuSkeleton = React.forwardRef< 655 + HTMLDivElement, 656 + React.ComponentProps<"div"> & { 657 + showIcon?: boolean 658 + } 659 + >(({ className, showIcon = false, ...props }, ref) => { 660 + // Random width between 50 to 90%. 661 + const width = React.useMemo(() => { 662 + return `${Math.floor(Math.random() * 40) + 50}%` 663 + }, []) 664 + 665 + return ( 666 + <div 667 + ref={ref} 668 + data-sidebar="menu-skeleton" 669 + className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)} 670 + {...props} 671 + > 672 + {showIcon && ( 673 + <Skeleton 674 + className="size-4 rounded-md" 675 + data-sidebar="menu-skeleton-icon" 676 + /> 677 + )} 678 + <Skeleton 679 + className="h-4 max-w-[--skeleton-width] flex-1" 680 + data-sidebar="menu-skeleton-text" 681 + style={ 682 + { 683 + "--skeleton-width": width, 684 + } as React.CSSProperties 685 + } 686 + /> 687 + </div> 688 + ) 689 + }) 690 + SidebarMenuSkeleton.displayName = "SidebarMenuSkeleton" 691 + 692 + const SidebarMenuSub = React.forwardRef< 693 + HTMLUListElement, 694 + React.ComponentProps<"ul"> 695 + >(({ className, ...props }, ref) => ( 696 + <ul 697 + ref={ref} 698 + data-sidebar="menu-sub" 699 + className={cn( 700 + "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5", 701 + "group-data-[collapsible=icon]:hidden", 702 + className 703 + )} 704 + {...props} 705 + /> 706 + )) 707 + SidebarMenuSub.displayName = "SidebarMenuSub" 708 + 709 + const SidebarMenuSubItem = React.forwardRef< 710 + HTMLLIElement, 711 + React.ComponentProps<"li"> 712 + >(({ ...props }, ref) => <li ref={ref} {...props} />) 713 + SidebarMenuSubItem.displayName = "SidebarMenuSubItem" 714 + 715 + const SidebarMenuSubButton = React.forwardRef< 716 + HTMLAnchorElement, 717 + React.ComponentProps<"a"> & { 718 + asChild?: boolean 719 + size?: "sm" | "md" 720 + isActive?: boolean 721 + } 722 + >(({ asChild = false, size = "md", isActive, className, ...props }, ref) => { 723 + const Comp = asChild ? Slot : "a" 724 + 725 + return ( 726 + <Comp 727 + ref={ref} 728 + data-sidebar="menu-sub-button" 729 + data-size={size} 730 + data-active={isActive} 731 + className={cn( 732 + "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground", 733 + "data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground", 734 + size === "sm" && "text-xs", 735 + size === "md" && "text-sm", 736 + "group-data-[collapsible=icon]:hidden", 737 + className 738 + )} 739 + {...props} 740 + /> 741 + ) 742 + }) 743 + SidebarMenuSubButton.displayName = "SidebarMenuSubButton" 744 + 745 + export { 746 + Sidebar, 747 + SidebarContent, 748 + SidebarFooter, 749 + SidebarGroup, 750 + SidebarGroupAction, 751 + SidebarGroupContent, 752 + SidebarGroupLabel, 753 + SidebarHeader, 754 + SidebarInput, 755 + SidebarInset, 756 + SidebarMenu, 757 + SidebarMenuAction, 758 + SidebarMenuBadge, 759 + SidebarMenuButton, 760 + SidebarMenuItem, 761 + SidebarMenuSkeleton, 762 + SidebarMenuSub, 763 + SidebarMenuSubButton, 764 + SidebarMenuSubItem, 765 + SidebarProvider, 766 + SidebarRail, 767 + SidebarSeparator, 768 + SidebarTrigger, 769 + useSidebar, 770 + }
+15
mast-react-vite/src/components/ui/skeleton.tsx
··· 1 + import { cn } from "@/lib/utils" 2 + 3 + function Skeleton({ 4 + className, 5 + ...props 6 + }: React.HTMLAttributes<HTMLDivElement>) { 7 + return ( 8 + <div 9 + className={cn("animate-pulse rounded-md bg-primary/10", className)} 10 + {...props} 11 + /> 12 + ) 13 + } 14 + 15 + export { Skeleton }
+26 -16
mast-react-vite/src/components/ui/task.tsx
··· 1 1 import { Separator } from "@/components/ui/separator" 2 + import { Badge } from "@/components/ui/badge" 3 + import { useSelection } from "@/contexts/selection-context" 2 4 3 5 interface TaskProps { 4 6 selected?: boolean ··· 7 9 } 8 10 9 11 export function Task({ selected, onSelect, data }: TaskProps) { 10 - const tagList = JSON.parse(data.tags).join(", ") 12 + const { isSelected, toggleSelection } = useSelection(); 13 + const tagList = JSON.parse(data.tags) 11 14 12 15 return ( 13 16 <> 14 17 <div 15 - className={`p-4 rounded-lg ${ 16 - selected ? 'bg-muted border-primary' : 'bg-card' 18 + className={`p-4 ${ 19 + isSelected(data.id) ? 'bg-muted border-primary' : 'bg-card' 17 20 } hover:bg-muted/50 transition-colors`} 18 - onClick={onSelect} 21 + onClick={() => toggleSelection(data.id)} 19 22 > 20 23 <div className="flex items-start gap-4"> 21 24 {/* Description - always shown */} 22 25 <div className="flex-1 min-w-0"> 23 - <p className="text-sm font-medium leading-none truncate min-h-6"> 24 - {data.description} 25 - </p> 26 - 27 - {/* Optional fields */} 28 - <div className="mt-1 flex flex-wrap gap-2"> 29 26 {data.project && ( 30 - <span className="text-xs text-muted-foreground"> 31 - Project: {data.project} 32 - </span> 27 + <div className="flex items-center"> 28 + <div className="w-2 h-2 rounded-full bg-blue-500"></div> 29 + <span className="text-xs text-muted-foreground leading-6 ml-1"> 30 + {data.project} 31 + </span> 32 + </div> 33 33 )} 34 + 35 + {/* Optional fields */} 36 + <div className="mt-1 flex flex-wrap gap-2 items-center"> 37 + <p className="text-sm font-medium leading-none truncate min-h-6 leading-6"> 38 + {data.description} 39 + </p> 34 40 {tagList.length > 0 && ( 35 - <span className="text-xs text-muted-foreground"> 36 - tags: {tagList} 37 - </span> 41 + <div className="flex gap-1 flex-wrap"> 42 + {tagList.map((tag: string) => ( 43 + <Badge key={tag} className="items-center text-xs bg-background border-muted-foreground text-muted-foreground"> 44 + # {tag} 45 + </Badge> 46 + ))} 47 + </div> 38 48 )} 39 49 {data.dueDate && ( 40 50 <span className="text-xs text-muted-foreground">
+30
mast-react-vite/src/components/ui/tooltip.tsx
··· 1 + import * as React from "react" 2 + import * as TooltipPrimitive from "@radix-ui/react-tooltip" 3 + 4 + import { cn } from "@/lib/utils" 5 + 6 + const TooltipProvider = TooltipPrimitive.Provider 7 + 8 + const Tooltip = TooltipPrimitive.Root 9 + 10 + const TooltipTrigger = TooltipPrimitive.Trigger 11 + 12 + const TooltipContent = React.forwardRef< 13 + React.ElementRef<typeof TooltipPrimitive.Content>, 14 + React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> 15 + >(({ className, sideOffset = 4, ...props }, ref) => ( 16 + <TooltipPrimitive.Portal> 17 + <TooltipPrimitive.Content 18 + ref={ref} 19 + sideOffset={sideOffset} 20 + className={cn( 21 + "z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", 22 + className 23 + )} 24 + {...props} 25 + /> 26 + </TooltipPrimitive.Portal> 27 + )) 28 + TooltipContent.displayName = TooltipPrimitive.Content.displayName 29 + 30 + export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
+41
mast-react-vite/src/contexts/selection-context.tsx
··· 1 + import { createContext, useContext, useState } from 'react'; 2 + 3 + type SelectionContextType = { 4 + selectedItems: Set<string>; 5 + toggleSelection: (id: string) => void; 6 + clearSelection: () => void; 7 + isSelected: (id: string) => boolean; 8 + }; 9 + 10 + const SelectionContext = createContext<SelectionContextType | undefined>(undefined); 11 + 12 + export function SelectionProvider({ children }) { 13 + const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set()); 14 + 15 + const toggleSelection = (id: string) => { 16 + setSelectedItems(prev => { 17 + const next = new Set(prev); 18 + if (next.has(id)) { 19 + next.delete(id); 20 + } else { 21 + next.add(id); 22 + } 23 + return next; 24 + }); 25 + }; 26 + 27 + const clearSelection = () => setSelectedItems(new Set()); 28 + const isSelected = (id: string) => selectedItems.has(id); 29 + 30 + return ( 31 + <SelectionContext.Provider value={{ selectedItems, toggleSelection, clearSelection, isSelected }}> 32 + {children} 33 + </SelectionContext.Provider> 34 + ); 35 + } 36 + 37 + export const useSelection = () => { 38 + const context = useContext(SelectionContext); 39 + if (!context) throw new Error('useSelection must be used within SelectionProvider'); 40 + return context; 41 + };
+19
mast-react-vite/src/hooks/use-mobile.tsx
··· 1 + import * as React from "react" 2 + 3 + const MOBILE_BREAKPOINT = 768 4 + 5 + export function useIsMobile() { 6 + const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined) 7 + 8 + React.useEffect(() => { 9 + const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) 10 + const onChange = () => { 11 + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 12 + } 13 + mql.addEventListener("change", onChange) 14 + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 15 + return () => mql.removeEventListener("change", onChange) 16 + }, []) 17 + 18 + return !!isMobile 19 + }
+16
mast-react-vite/src/index.css
··· 29 29 --chart-3: 197 37% 24%; 30 30 --chart-4: 43 74% 66%; 31 31 --chart-5: 27 87% 67%; 32 + --sidebar-background: 0 0% 98%; 33 + --sidebar-foreground: 240 5.3% 26.1%; 34 + --sidebar-primary: 240 5.9% 10%; 35 + --sidebar-primary-foreground: 0 0% 98%; 36 + --sidebar-accent: 240 4.8% 95.9%; 37 + --sidebar-accent-foreground: 240 5.9% 10%; 38 + --sidebar-border: 220 13% 91%; 39 + --sidebar-ring: 217.2 91.2% 59.8%; 32 40 } 33 41 34 42 .dark { ··· 56 64 --chart-3: 30 80% 55%; 57 65 --chart-4: 280 65% 60%; 58 66 --chart-5: 340 75% 55%; 67 + --sidebar-background: 240 5.9% 10%; 68 + --sidebar-foreground: 240 4.8% 95.9%; 69 + --sidebar-primary: 224.3 76.3% 48%; 70 + --sidebar-primary-foreground: 0 0% 100%; 71 + --sidebar-accent: 240 3.7% 15.9%; 72 + --sidebar-accent-foreground: 240 4.8% 95.9%; 73 + --sidebar-border: 240 3.7% 15.9%; 74 + --sidebar-ring: 217.2 91.2% 59.8%; 59 75 } 60 76 } 61 77
+5 -1
mast-react-vite/src/main.tsx
··· 7 7 import wasmUrl from '@vlcn.io/crsqlite-wasm/crsqlite.wasm?url'; 8 8 import tblrx from '@vlcn.io/rx-tbl'; 9 9 10 + import { SelectionProvider } from "@/contexts/selection-context" 11 + 10 12 const initDb = async () => { 11 13 const sqlite = await initWasm(() => wasmUrl); 12 14 const db: DBAsync = await sqlite.open("todo.db"); ··· 31 33 const init = async () => { 32 34 const ctx = await initDb(); 33 35 createRoot(document.getElementById("root") as HTMLElement).render( 34 - <main className="min-h-screen flex flex-col py-12 bg-background text-gray-200"> 36 + <main className="h-screen flex flex-col bg-background text-gray-200"> 37 + <SelectionProvider> 35 38 <App ctx={ctx} /> 39 + </SelectionProvider> 36 40 </main> 37 41 ); 38 42 }
+81 -63
mast-react-vite/tailwind.config.js
··· 9 9 ], 10 10 prefix: "", 11 11 theme: { 12 - container: { 13 - center: true, 14 - padding: "2rem", 15 - screens: { 16 - "2xl": "1400px", 17 - }, 18 - }, 19 - extend: { 20 - colors: { 21 - border: "hsl(var(--border))", 22 - input: "hsl(var(--input))", 23 - ring: "hsl(var(--ring))", 24 - background: "hsl(var(--background))", 25 - foreground: "hsl(var(--foreground))", 26 - primary: { 27 - DEFAULT: "hsl(var(--primary))", 28 - foreground: "hsl(var(--primary-foreground))", 29 - }, 30 - secondary: { 31 - DEFAULT: "hsl(var(--secondary))", 32 - foreground: "hsl(var(--secondary-foreground))", 33 - }, 34 - destructive: { 35 - DEFAULT: "hsl(var(--destructive))", 36 - foreground: "hsl(var(--destructive-foreground))", 37 - }, 38 - muted: { 39 - DEFAULT: "hsl(var(--muted))", 40 - foreground: "hsl(var(--muted-foreground))", 41 - }, 42 - accent: { 43 - DEFAULT: "hsl(var(--accent))", 44 - foreground: "hsl(var(--accent-foreground))", 45 - }, 46 - popover: { 47 - DEFAULT: "hsl(var(--popover))", 48 - foreground: "hsl(var(--popover-foreground))", 49 - }, 50 - card: { 51 - DEFAULT: "hsl(var(--card))", 52 - foreground: "hsl(var(--card-foreground))", 53 - }, 54 - }, 55 - borderRadius: { 56 - lg: "var(--radius)", 57 - md: "calc(var(--radius) - 2px)", 58 - sm: "calc(var(--radius) - 4px)", 59 - }, 60 - keyframes: { 61 - "accordion-down": { 62 - from: { height: "0" }, 63 - to: { height: "var(--radix-accordion-content-height)" }, 64 - }, 65 - "accordion-up": { 66 - from: { height: "var(--radix-accordion-content-height)" }, 67 - to: { height: "0" }, 68 - }, 69 - }, 70 - animation: { 71 - "accordion-down": "accordion-down 0.2s ease-out", 72 - "accordion-up": "accordion-up 0.2s ease-out", 73 - }, 74 - }, 12 + container: { 13 + center: true, 14 + padding: '2rem', 15 + screens: { 16 + '2xl': '1400px' 17 + } 18 + }, 19 + extend: { 20 + colors: { 21 + border: 'hsl(var(--border))', 22 + input: 'hsl(var(--input))', 23 + ring: 'hsl(var(--ring))', 24 + background: 'hsl(var(--background))', 25 + foreground: 'hsl(var(--foreground))', 26 + primary: { 27 + DEFAULT: 'hsl(var(--primary))', 28 + foreground: 'hsl(var(--primary-foreground))' 29 + }, 30 + secondary: { 31 + DEFAULT: 'hsl(var(--secondary))', 32 + foreground: 'hsl(var(--secondary-foreground))' 33 + }, 34 + destructive: { 35 + DEFAULT: 'hsl(var(--destructive))', 36 + foreground: 'hsl(var(--destructive-foreground))' 37 + }, 38 + muted: { 39 + DEFAULT: 'hsl(var(--muted))', 40 + foreground: 'hsl(var(--muted-foreground))' 41 + }, 42 + accent: { 43 + DEFAULT: 'hsl(var(--accent))', 44 + foreground: 'hsl(var(--accent-foreground))' 45 + }, 46 + popover: { 47 + DEFAULT: 'hsl(var(--popover))', 48 + foreground: 'hsl(var(--popover-foreground))' 49 + }, 50 + card: { 51 + DEFAULT: 'hsl(var(--card))', 52 + foreground: 'hsl(var(--card-foreground))' 53 + }, 54 + sidebar: { 55 + DEFAULT: 'hsl(var(--sidebar-background))', 56 + foreground: 'hsl(var(--sidebar-foreground))', 57 + primary: 'hsl(var(--sidebar-primary))', 58 + 'primary-foreground': 'hsl(var(--sidebar-primary-foreground))', 59 + accent: 'hsl(var(--sidebar-accent))', 60 + 'accent-foreground': 'hsl(var(--sidebar-accent-foreground))', 61 + border: 'hsl(var(--sidebar-border))', 62 + ring: 'hsl(var(--sidebar-ring))' 63 + } 64 + }, 65 + borderRadius: { 66 + lg: 'var(--radius)', 67 + md: 'calc(var(--radius) - 2px)', 68 + sm: 'calc(var(--radius) - 4px)' 69 + }, 70 + keyframes: { 71 + 'accordion-down': { 72 + from: { 73 + height: '0' 74 + }, 75 + to: { 76 + height: 'var(--radix-accordion-content-height)' 77 + } 78 + }, 79 + 'accordion-up': { 80 + from: { 81 + height: 'var(--radix-accordion-content-height)' 82 + }, 83 + to: { 84 + height: '0' 85 + } 86 + } 87 + }, 88 + animation: { 89 + 'accordion-down': 'accordion-down 0.2s ease-out', 90 + 'accordion-up': 'accordion-up 0.2s ease-out' 91 + } 92 + } 75 93 }, 76 94 plugins: [require("tailwindcss-animate")], 77 95 }