diff --git a/.prettierrc b/.prettierrc index 97cce81e..13710b70 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,8 +1,11 @@ { - "plugins": ["prettier-plugin-tailwindcss"], + "plugins": [ + "prettier-plugin-tailwindcss" + ], "tabWidth": 2, "useTabs": false, "singleQuote": false, "trailingComma": "es5", - "semi": true -} + "semi": true, + "printWidth": 120 +} \ No newline at end of file diff --git a/README.md b/README.md index 6830f493..f38af483 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +
+ +
+ # Remix Development Tools ![GitHub Repo stars](https://img.shields.io/github/stars/Code-Forge-Net/Remix-Dev-Tools?style=social) @@ -16,6 +20,18 @@ Remix Development Tools is an open-source package designed to enhance your devel ### Timeline ![timeline](./assets/timeline.gif) +## What's new? + +### v2.1.0 + Detached mode support! + + +Json viewer improvements: +- Number of items in objects/arrays +- Copy to clipboard +- type of the value +- Doesn't close on revalidate anymore +- Different UI ## Features @@ -57,6 +73,10 @@ The terminal tab allows you to run terminal commands from the Remix Dev Tools. T - You can press `Ctrl + C` to cancel the current command. - You can press `Ctrl + L` to clear the terminal. +### Detached mode + +Detached mode allows you to un-dock the Remix Dev Tools from the browser and move it to a separate window. This is useful if you want to have the dev tools open on a separate monitor or if you want to have it open on a separate window on the same monitor. + ## Getting Started To install and utilize Remix Development Tools, follow these steps: diff --git a/assets/remix-dev-tools.png b/assets/remix-dev-tools.png new file mode 100644 index 00000000..b3cb9186 Binary files /dev/null and b/assets/remix-dev-tools.png differ diff --git a/package-lock.json b/package-lock.json index 1e11a1f1..697d8551 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "remix-development-tools", - "version": "2.0.0", + "version": "2.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "remix-development-tools", - "version": "2.0.0", + "version": "2.1.0", "license": "MIT", "workspaces": [ ".", @@ -16,9 +16,9 @@ "dependencies": { "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-select": "^1.2.2", + "@uiw/react-json-view": "^1.8.4", "clsx": "^2.0.0", "lucide-react": "^0.263.1", - "react-json-view-lite": "^0.9.7", "react-use-websocket": "^4.3.1", "tailwind-merge": "^1.14.0" }, @@ -1846,11 +1846,11 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", + "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -6194,6 +6194,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@uiw/react-json-view": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@uiw/react-json-view/-/react-json-view-1.8.4.tgz", + "integrity": "sha512-XdvGhYTfCbsYumYs8dR6IuOzMa9TcmegaDQTbTax2wl1SgMIWh0VU750OGxOsTBSALNoR5lYjIh8Y56deBIKXg==", + "dependencies": { + "@babel/runtime": "^7.22.6" + }, + "peerDependencies": { + "@babel/runtime": ">=7.10.0", + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, "node_modules/@vanilla-extract/babel-plugin-debug-ids": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@vanilla-extract/babel-plugin-debug-ids/-/babel-plugin-debug-ids-1.0.3.tgz", @@ -17274,17 +17287,6 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "node_modules/react-json-view-lite": { - "version": "0.9.7", - "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-0.9.7.tgz", - "integrity": "sha512-JWdrKYWac+sGO8aIFJ0tZw/cTSdgab7pS5Rnmv2yTjt/yEz2Ej4OvKYUe1ZXJlQDj7YaoZPUDF88NTk2Oubucg==", - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/react-property": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz", @@ -17561,9 +17563,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/regenerator-transform": { "version": "0.15.1", @@ -23017,11 +23019,11 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", + "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", "requires": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" } }, "@babel/template": { @@ -25893,6 +25895,14 @@ "eslint-visitor-keys": "^3.3.0" } }, + "@uiw/react-json-view": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@uiw/react-json-view/-/react-json-view-1.8.4.tgz", + "integrity": "sha512-XdvGhYTfCbsYumYs8dR6IuOzMa9TcmegaDQTbTax2wl1SgMIWh0VU750OGxOsTBSALNoR5lYjIh8Y56deBIKXg==", + "requires": { + "@babel/runtime": "^7.22.6" + } + }, "@vanilla-extract/babel-plugin-debug-ids": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@vanilla-extract/babel-plugin-debug-ids/-/babel-plugin-debug-ids-1.0.3.tgz", @@ -33987,12 +33997,6 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "react-json-view-lite": { - "version": "0.9.7", - "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-0.9.7.tgz", - "integrity": "sha512-JWdrKYWac+sGO8aIFJ0tZw/cTSdgab7pS5Rnmv2yTjt/yEz2Ej4OvKYUe1ZXJlQDj7YaoZPUDF88NTk2Oubucg==", - "requires": {} - }, "react-property": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz", @@ -34193,9 +34197,9 @@ } }, "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "regenerator-transform": { "version": "0.15.1", @@ -34502,6 +34506,7 @@ "@types/react-dom": "^18.2.7", "@typescript-eslint/eslint-plugin": "^5.57.1", "@typescript-eslint/parser": "^5.57.1", + "@uiw/react-json-view": "^1.8.4", "@vitejs/plugin-react": "^4.0.3", "@vitest/coverage-v8": "^0.33.0", "autoprefixer": "^10.4.14", @@ -34520,7 +34525,6 @@ "prettier-plugin-tailwindcss": "^0.4.1", "react-dom": "^18.2.0", "react-hook-form": "^7.45.2", - "react-json-view-lite": "^0.9.7", "react-use-websocket": "^4.3.1", "remix-app-for-testing": "file:src/remix-app-for-testing", "remix-development-tools": "file:", @@ -35722,11 +35726,11 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", + "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", "requires": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" } }, "@babel/template": { @@ -38598,6 +38602,14 @@ "eslint-visitor-keys": "^3.3.0" } }, + "@uiw/react-json-view": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@uiw/react-json-view/-/react-json-view-1.8.4.tgz", + "integrity": "sha512-XdvGhYTfCbsYumYs8dR6IuOzMa9TcmegaDQTbTax2wl1SgMIWh0VU750OGxOsTBSALNoR5lYjIh8Y56deBIKXg==", + "requires": { + "@babel/runtime": "^7.22.6" + } + }, "@vanilla-extract/babel-plugin-debug-ids": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@vanilla-extract/babel-plugin-debug-ids/-/babel-plugin-debug-ids-1.0.3.tgz", @@ -46692,12 +46704,6 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "react-json-view-lite": { - "version": "0.9.7", - "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-0.9.7.tgz", - "integrity": "sha512-JWdrKYWac+sGO8aIFJ0tZw/cTSdgab7pS5Rnmv2yTjt/yEz2Ej4OvKYUe1ZXJlQDj7YaoZPUDF88NTk2Oubucg==", - "requires": {} - }, "react-property": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz", @@ -46898,9 +46904,9 @@ } }, "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "regenerator-transform": { "version": "0.15.1", diff --git a/package.json b/package.json index 677717b8..97366659 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,15 @@ "name": "remix-development-tools", "description": "Remix development tools.", "author": "Alem Tuzlak", - "version": "2.0.0", + "version": "2.1.0", "license": "MIT", "keywords": [ "remix", - "remix-dev-tools" + "remix-dev-tools", + "remix-development-tools", + "remix-debugger", + "remix-debugger-ui", + "remix-debugger-ui-react" ], "private": false, "type": "module", @@ -98,10 +102,10 @@ "dependencies": { "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-select": "^1.2.2", + "@uiw/react-json-view": "^1.8.4", "clsx": "^2.0.0", "lucide-react": "^0.263.1", - "react-json-view-lite": "^0.9.7", "react-use-websocket": "^4.3.1", "tailwind-merge": "^1.14.0" } -} +} \ No newline at end of file diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 00000000..76da2c3b --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,25 @@ +# Plugins + +This folder contains all the ready to go plugins that you can copy/paste into your project. + +If you build a plugin please feel free to create a PR towards the `plugins` folder so we can add it to the list of plugins. + +## How to use + +Each plugin has a `README.md` file that explains how to use it. + + +So all you need to do is find the one you like, copy the code and paste it into your project and follow the instructions from the `README.md` file. + +## Can I add my own features? + +All the plugins featured under this folder are meant to be copy/pasted into your project with you having all the rights to modify them as you see fit. Feel free to add/remove whatever you like. If you add something cool, please share it with us so we can add it to the list of plugins or improve the existing ones. + +## How to add a new plugin + +1. Fork the repo +2. Create a new folder under `plugins` with the name of your plugin +3. Add a `README.md` file with the instructions on how to use the plugin +4. Add TODO's in the code where the user needs to modify the code to their project specifications +5. Add an image/video/gif of the plugin in action +6. Create a PR towards the repository! \ No newline at end of file diff --git a/plugins/icon-library/Icon library.mp4 b/plugins/icon-library/Icon library.mp4 new file mode 100644 index 00000000..523a1fc8 Binary files /dev/null and b/plugins/icon-library/Icon library.mp4 differ diff --git a/plugins/icon-library/README.md b/plugins/icon-library/README.md new file mode 100644 index 00000000..e5ca1165 --- /dev/null +++ b/plugins/icon-library/README.md @@ -0,0 +1,41 @@ +# Icon library plugin + +This plugin allows you to see all your project icons in a new tab in remix development tools, copy the code and change their classes. + + + +## How to use + +1. Copy the code from the plugin located in this folder. +2. Go over the TODO's in the code and modify the code to your project specifications. +3. Import the plugin exported from the `icon-library.tsx` into your `root.tsx` file. +4. Add the plugin to the `plugins` array in the `RemixDevTools` component. + +```tsx + import { iconLibraryPlugin } from "~/icon-library.tsx"; + + +``` + +5. Run your project and open the new tab in the development tools. + +## How it works + +The plugin will use all the icons in your project that are provided to it and will display them in a grid with different sizes. + +You can click on the icon to copy the code of the icon to your clipboard. + +You can use the input on the top right to add custom classes to the component (eg. change colors on the fly). + +## How to add icons + +This will be easy/hard depending on your project setup. The basic idea is to have an icon component that is reusable across the project by +providing a different name and size to the component. If you do not have this you would probably need to do it in a different way. What is +important is to have an array of icon names in the project that you can use to generate the icons. + +## Can I add my own features? + +All the plugins featured under this folder are meant to be copy/pasted into your project with you having all the rights to modify them as you see fit. Feel free to add/remove whatever you like. If you add something cool, please share it with us so we can add it to the list of plugins or improve the existing ones. \ No newline at end of file diff --git a/plugins/icon-library/icon-library.tsx b/plugins/icon-library/icon-library.tsx new file mode 100644 index 00000000..6f2a568c --- /dev/null +++ b/plugins/icon-library/icon-library.tsx @@ -0,0 +1,89 @@ +import React, { useState } from "react"; +import clsx from "clsx"; +import type { Plugin } from "remix-development-tools"; +// TODO Replace these with your own toast library +//import { toast } from "react-toastify"; +// TODO Replace these with your own array of all icon names available through a project, either generate through a script or use epic-stack script +const iconNames = []; +// TODO Import this type from your icon component +interface IconProps { + name: string; + size: "sm" | "md" | "lg" | "xl"; + className?: string; + onClick?: () => void; +} +// TODO Import your icon component +const Icon = (props: IconProps) => { + return
; +}; + +// Icon Library part +// Allows you to copy an icon with a toast notification, modify the code to fit your needs +const ClickableIcon = ({ name, size, ...props }: IconProps) => { + const [clicked, setClicked] = React.useState(false); + const copyIcon = () => { + setClicked(true); + // Shows toast that you copied the icon + //toast("Copied to clipboard"); + // Writes the icon to the clipboard + navigator.clipboard.writeText( + `` + ); + // Reverts the icon from checked to normal after 1.5 seconds + setTimeout(() => { + setClicked(false); + }, 1500); + }; + return ( + + ); +}; + +const IconLibrary = () => { + const [iconClasses, setIconClasses] = useState(""); + return ( +
+
+ + setIconClasses(e.target.value)} + /> +
+
+ {iconNames.map((key) => { + return ( +
+
{key}
+
+ + + + +
+
+ ); + })} +
+
+ ); +}; + +// TODO Import this into your root.tsx and call it inside of the plugins array for RemixDevTools +export const iconLibraryPlugin: Plugin = () => ({ + // TODO Replace with your own icon + icon: , + component: , + name: "Icon Library", + id: "icon-library", + requiresForge: false, + hideTimeline: true, +}); diff --git a/src/RemixDevTools/RemixDevTools.tsx b/src/RemixDevTools/RemixDevTools.tsx index 387ef594..e8dbca39 100644 --- a/src/RemixDevTools/RemixDevTools.tsx +++ b/src/RemixDevTools/RemixDevTools.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import { RDTContextProvider } from "./context/RDTContext"; import { Tab } from "./tabs"; import { useTimelineHandler } from "./hooks/useTimelineHandler"; -import { usePersistOpen, useSettingsContext } from "./context/useRDTContext"; +import { useDetachedWindowControls, usePersistOpen, useSettingsContext } from "./context/useRDTContext"; import { useLocation } from "@remix-run/react"; import { Trigger } from "./components/Trigger"; import { MainPanel } from "./layout/MainPanel"; @@ -10,25 +10,34 @@ import { Tabs } from "./layout/Tabs"; import { ContentPanel } from "./layout/ContentPanel"; import rdtStylesheet from "../input.css?inline"; import { useOutletAugment } from "./hooks/useOutletAugment"; +import { useResetDetachmentCheck } from "./hooks/detached/useResetDetachmentCheck"; +import { useSetRouteBoundaries } from "./hooks/useSetRouteBoundaries"; +import { REMIX_DEV_TOOLS } from "./utils/storage"; +import { useSyncStateWhenDetached } from "./hooks/detached/useSyncStateWhenDetached"; -type Props = RemixDevToolsProps; +const InjectedStyles = () =>