From 53c31307c11dcae7ec9766424d4ab36c1754b806 Mon Sep 17 00:00:00 2001 From: mohitmalibetterbugs <147377846+mohitmalibetterbugs@users.noreply.github.com> Date: Tue, 26 May 2026 16:31:06 +0530 Subject: [PATCH 1/5] Merge DEV (#91) * feat(ui): add reusable CopyButton and refactor wordCounter and jsonToTxt Adds a reusable CopyButton component and refactors WordCounter and JsonToTxt to use it. Fixes #17 * chore(release): 1.4.0-develop.1 [skip ci] # [1.4.0-develop.1](https://github.com/betterbugs/dev-tools/compare/v1.3.2...v1.4.0-develop.1) (2026-02-28) ### Features * **ui:** add reusable CopyButton and refactor wordCounter and jsonToTxt ([d5b9e83](https://github.com/betterbugs/dev-tools/commit/d5b9e8333673c5254cf39529a90869b1b741e385)), closes [#17](https://github.com/betterbugs/dev-tools/issues/17) * fix(tools): implement proper bcrypt generator Replaces placeholder hashing logic with bcryptjs implementation as contributed in PR #23 Adds proper salt generation and verification using bcrypt.compare. Fixes #13 * chore(release): 1.4.0-develop.2 [skip ci] # [1.4.0-develop.2](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.1...v1.4.0-develop.2) (2026-02-28) ### Bug Fixes * **tools:** implement proper bcrypt generator ([94d19be](https://github.com/betterbugs/dev-tools/commit/94d19be7e4b8d9256557e7668898ec4d6c3ca15c)), closes [#23](https://github.com/betterbugs/dev-tools/issues/23) [#13](https://github.com/betterbugs/dev-tools/issues/13) * Add Curl to Code Converter (#25) closes: #21 Co-authored-by: Syed Fahad * feat: Add Smart Repair feature to JSON Validator (#41) Closes #38 * feat. json to csv convertor (#26) * feat. json to csv convertor * align checkbox Fixes #18 * chore: initialize eslint configuration * feat: Add IPv4 Subnet Calculator Tool This pull request implements a specialized IPv4 Subnet Calculator tool for network engineers and DevOps professionals. The tool simplifies network planning and infrastructure setup by instantly calculating subnet details from an IP address and CIDR prefix or subnet mask. closes #33 * chore: sync package-lock with package.json * chore(release): 1.4.0-develop.3 [skip ci] # [1.4.0-develop.3](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.2...v1.4.0-develop.3) (2026-03-03) ### Features * Add IPv4 Subnet Calculator Tool ([ad1c03f](https://github.com/betterbugs/dev-tools/commit/ad1c03fd0065f0cfce409b72882188dc7de630d0)), closes [#33](https://github.com/betterbugs/dev-tools/issues/33) * Add Smart Repair feature to JSON Validator ([#41](https://github.com/betterbugs/dev-tools/issues/41)) ([7a3c7a5](https://github.com/betterbugs/dev-tools/commit/7a3c7a5008d4236d954e1c20482635b0a0da5ef0)), closes [#38](https://github.com/betterbugs/dev-tools/issues/38) * feat: Add lockfile guard workflow to prevent unintended lockfile changes * chore(release): 1.4.0-develop.4 [skip ci] # [1.4.0-develop.4](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.3...v1.4.0-develop.4) (2026-03-03) ### Features * Add lockfile guard workflow to prevent unintended lockfile changes ([aa20fb5](https://github.com/betterbugs/dev-tools/commit/aa20fb5422aae56e9d80f7472a6f974624431572)) * feat(tools): add SVG to React/CSS utility * feat(tools): add SVG to React/CSS utility Add SVG converter tool that transforms raw SVG code into optimized variants: - React Component: Clean, reusable functional component with dynamic sizing - CSS Data URI: Inline SVG for CSS background images - CSS Mask: SVG as CSS mask-image for flexible icon styling Features: - Automatic metadata cleanup (removes XML declarations, comments, DOCTYPE) - viewBox preservation for responsive sizing - Optional currentColor replacement for theme support - Configurable default width/height - File upload support (.svg files) - Copy-to-clipboard functionality Closes #50 * fix(release): update GITHUB_TOKEN to use RELEASE_TOKEN for semantic release * chore(release): 1.4.0-develop.5 [skip ci] # [1.4.0-develop.5](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.4...v1.4.0-develop.5) (2026-03-05) ### Bug Fixes * **release:** update GITHUB_TOKEN to use RELEASE_TOKEN for semantic release ([be3a012](https://github.com/betterbugs/dev-tools/commit/be3a012c6d7df84ab5826ce03268ec8aad402c15)) ### Features * **tools:** add SVG to React/CSS utility ([218ccad](https://github.com/betterbugs/dev-tools/commit/218ccad3c5eb7121a9bd7319147520eb39713695)), closes [#50](https://github.com/betterbugs/dev-tools/issues/50) * Favourite Feature Added (#77) Added a favourite tool feature. Favourite tools are pushed to top. Added a filter for favourite tools. Closes #61 * feat: Add Unix Timestamp (Epoch) Converter Utility Closes: #16 * chore(release): 1.4.0-develop.6 [skip ci] # [1.4.0-develop.6](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.5...v1.4.0-develop.6) (2026-03-08) ### Features * Add Unix Timestamp (Epoch) Converter Utility ([f277272](https://github.com/betterbugs/dev-tools/commit/f27727267639f54e4ffaa80919b1d0836621ac7d)), closes [#16](https://github.com/betterbugs/dev-tools/issues/16) * feat(tools): add Unix Timestamp Converter to development tools list * chore(release): 1.4.0-develop.7 [skip ci] # [1.4.0-develop.7](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.6...v1.4.0-develop.7) (2026-03-08) ### Features * **tools:** add Unix Timestamp Converter to development tools list ([3fedf57](https://github.com/betterbugs/dev-tools/commit/3fedf57f4036f7081b37c8ca1b3c585ea1e62045)) * feat: Added URL parser & Query Editor Tool Closes : #51 * chore(release): 1.4.0-develop.8 [skip ci] # [1.4.0-develop.8](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.7...v1.4.0-develop.8) (2026-03-08) ### Features * Added URL parser & Query Editor Tool ([c9933ba](https://github.com/betterbugs/dev-tools/commit/c9933bae3cfbeb65c210f6877abf367c3cb0f46e)), closes [#51](https://github.com/betterbugs/dev-tools/issues/51) * feat: add class-validator dependency and update page styles - Added `class-validator` package to `package.json`. - Adjusted styles in `page.tsx` for sidebar positioning and button margin. - Refined text styles in `[slug]/page.tsx` for better readability. - Updated descriptions in `constants.tsx` for JSON tools to enhance clarity. * feature: add light mode toggle and global theme support #29 Closes: #14 * feat: add class-validator dependency and update page styles (#81) - Added `class-validator` package to `package.json`. - Adjusted styles in `page.tsx` for sidebar positioning and button margin. - Refined text styles in `[slug]/page.tsx` for better readability. - Updated descriptions in `constants.tsx` for JSON tools to enhance clarity. Co-authored-by: Mohit Mali * chore(release): 1.4.0-develop.9 [skip ci] # [1.4.0-develop.9](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.8...v1.4.0-develop.9) (2026-04-14) ### Features * add class-validator dependency and update page styles ([#81](https://github.com/betterbugs/dev-tools/issues/81)) ([67f1aeb](https://github.com/betterbugs/dev-tools/commit/67f1aeb5a82cad25f2c8bb3dcdc67e453b62cee2)) * feat: add Image Resizer and Time Calculator components - Introduced Image Resizer component for local image resizing with format selection and aspect ratio options. - Added Time Calculator component for performing arithmetic operations on time values and calculating durations between dates. - Updated constants and routes to include new tools in the development tools list. - Refined styles in development tools for better UI consistency. * Dev tools (#83) * feat: add class-validator dependency and update page styles - Added `class-validator` package to `package.json`. - Adjusted styles in `page.tsx` for sidebar positioning and button margin. - Refined text styles in `[slug]/page.tsx` for better readability. - Updated descriptions in `constants.tsx` for JSON tools to enhance clarity. * feat: add Image Resizer and Time Calculator components - Introduced Image Resizer component for local image resizing with format selection and aspect ratio options. - Added Time Calculator component for performing arithmetic operations on time values and calculating durations between dates. - Updated constants and routes to include new tools in the development tools list. - Refined styles in development tools for better UI consistency. --------- Co-authored-by: zeel0m * Refine Image Resizer tool descriptions and styles - Updated the title of the Image Resizer to "Image Resizer Online" for clarity. - Enhanced the tool's description to better convey its features and usage. - Improved the step-by-step guide for using the Image Resizer, including clearer instructions and additional details on output preferences. - Adjusted text styles in `[slug]/page.tsx` for better readability. * Dev tools (#84) * feat: add class-validator dependency and update page styles - Added `class-validator` package to `package.json`. - Adjusted styles in `page.tsx` for sidebar positioning and button margin. - Refined text styles in `[slug]/page.tsx` for better readability. - Updated descriptions in `constants.tsx` for JSON tools to enhance clarity. * feat: add Image Resizer and Time Calculator components - Introduced Image Resizer component for local image resizing with format selection and aspect ratio options. - Added Time Calculator component for performing arithmetic operations on time values and calculating durations between dates. - Updated constants and routes to include new tools in the development tools list. - Refined styles in development tools for better UI consistency. * Refine Image Resizer tool descriptions and styles - Updated the title of the Image Resizer to "Image Resizer Online" for clarity. - Enhanced the tool's description to better convey its features and usage. - Improved the step-by-step guide for using the Image Resizer, including clearer instructions and additional details on output preferences. - Adjusted text styles in `[slug]/page.tsx` for better readability. --------- Co-authored-by: zeel0m * Refactor Time Calculator and Update Page Styles - Simplified comments in `[slug]/page.tsx` for clarity. - Enhanced `TimeCalculator` component with new features: added row management and keyboard navigation for input fields. - Introduced `useRef` for better DOM manipulation and focused input handling. - Improved user experience by allowing dynamic row addition and input focus on Enter key press. * Dev tools (#86) * feat: add class-validator dependency and update page styles - Added `class-validator` package to `package.json`. - Adjusted styles in `page.tsx` for sidebar positioning and button margin. - Refined text styles in `[slug]/page.tsx` for better readability. - Updated descriptions in `constants.tsx` for JSON tools to enhance clarity. * feat: add Image Resizer and Time Calculator components - Introduced Image Resizer component for local image resizing with format selection and aspect ratio options. - Added Time Calculator component for performing arithmetic operations on time values and calculating durations between dates. - Updated constants and routes to include new tools in the development tools list. - Refined styles in development tools for better UI consistency. * Refine Image Resizer tool descriptions and styles - Updated the title of the Image Resizer to "Image Resizer Online" for clarity. - Enhanced the tool's description to better convey its features and usage. - Improved the step-by-step guide for using the Image Resizer, including clearer instructions and additional details on output preferences. - Adjusted text styles in `[slug]/page.tsx` for better readability. * Refactor Time Calculator and Update Page Styles - Simplified comments in `[slug]/page.tsx` for clarity. - Enhanced `TimeCalculator` component with new features: added row management and keyboard navigation for input fields. - Introduced `useRef` for better DOM manipulation and focused input handling. - Improved user experience by allowing dynamic row addition and input focus on Enter key press. --------- Co-authored-by: zeel0m * Enhance Development Tools with New Features and Improvements - Updated the description splitting logic in `[slug]/page.tsx` to handle quoted text more accurately. - Improved text styling for quoted and unquoted parts in descriptions for better readability. - Added new `HarFileViewer` component for inspecting HAR files, including parsing and displaying network request data. - Introduced `HtmlViewer` component with enhanced file upload and editor functionalities. - Added `SvgViewer` component for safe SVG markup preview and editing. - Updated constants and routes to include new tools in the development tools list, enhancing user navigation and accessibility. * Dev tools (#87) * feat: add class-validator dependency and update page styles - Added `class-validator` package to `package.json`. - Adjusted styles in `page.tsx` for sidebar positioning and button margin. - Refined text styles in `[slug]/page.tsx` for better readability. - Updated descriptions in `constants.tsx` for JSON tools to enhance clarity. * feat: add Image Resizer and Time Calculator components - Introduced Image Resizer component for local image resizing with format selection and aspect ratio options. - Added Time Calculator component for performing arithmetic operations on time values and calculating durations between dates. - Updated constants and routes to include new tools in the development tools list. - Refined styles in development tools for better UI consistency. * Refine Image Resizer tool descriptions and styles - Updated the title of the Image Resizer to "Image Resizer Online" for clarity. - Enhanced the tool's description to better convey its features and usage. - Improved the step-by-step guide for using the Image Resizer, including clearer instructions and additional details on output preferences. - Adjusted text styles in `[slug]/page.tsx` for better readability. * Refactor Time Calculator and Update Page Styles - Simplified comments in `[slug]/page.tsx` for clarity. - Enhanced `TimeCalculator` component with new features: added row management and keyboard navigation for input fields. - Introduced `useRef` for better DOM manipulation and focused input handling. - Improved user experience by allowing dynamic row addition and input focus on Enter key press. * Enhance Development Tools with New Features and Improvements - Updated the description splitting logic in `[slug]/page.tsx` to handle quoted text more accurately. - Improved text styling for quoted and unquoted parts in descriptions for better readability. - Added new `HarFileViewer` component for inspecting HAR files, including parsing and displaying network request data. - Introduced `HtmlViewer` component with enhanced file upload and editor functionalities. - Added `SvgViewer` component for safe SVG markup preview and editing. - Updated constants and routes to include new tools in the development tools list, enhancing user navigation and accessibility. --------- Co-authored-by: zeel0m Co-authored-by: Mohit Mali * Update development tools UI and enhance documentation - Modified styles in `[slug]/page.tsx` for the tools panel to improve visual consistency. - Added a new pro tip in `developmentToolsConstant.tsx` regarding the use of `btoa()` with emojis. - Refined step descriptions for the Image Resizer tool to clarify output dimensions and export options. * Add Base64 and Image Conversion Tools - Introduced `Base64ToImageConverter` and `ImageToBase64Converter` components for converting between image files and Base64 strings. - Updated `constants.tsx` to include new tools in the development tools list and adjusted routes accordingly. - Enhanced the `epochConverter` component with additional icons and improved UI for better user experience. - Refined descriptions in `developmentToolsConstant.tsx` to clarify tool functionalities and usage. * Dev tools (#88) * feat: add class-validator dependency and update page styles - Added `class-validator` package to `package.json`. - Adjusted styles in `page.tsx` for sidebar positioning and button margin. - Refined text styles in `[slug]/page.tsx` for better readability. - Updated descriptions in `constants.tsx` for JSON tools to enhance clarity. * feat: add Image Resizer and Time Calculator components - Introduced Image Resizer component for local image resizing with format selection and aspect ratio options. - Added Time Calculator component for performing arithmetic operations on time values and calculating durations between dates. - Updated constants and routes to include new tools in the development tools list. - Refined styles in development tools for better UI consistency. * Refine Image Resizer tool descriptions and styles - Updated the title of the Image Resizer to "Image Resizer Online" for clarity. - Enhanced the tool's description to better convey its features and usage. - Improved the step-by-step guide for using the Image Resizer, including clearer instructions and additional details on output preferences. - Adjusted text styles in `[slug]/page.tsx` for better readability. * Refactor Time Calculator and Update Page Styles - Simplified comments in `[slug]/page.tsx` for clarity. - Enhanced `TimeCalculator` component with new features: added row management and keyboard navigation for input fields. - Introduced `useRef` for better DOM manipulation and focused input handling. - Improved user experience by allowing dynamic row addition and input focus on Enter key press. * Enhance Development Tools with New Features and Improvements - Updated the description splitting logic in `[slug]/page.tsx` to handle quoted text more accurately. - Improved text styling for quoted and unquoted parts in descriptions for better readability. - Added new `HarFileViewer` component for inspecting HAR files, including parsing and displaying network request data. - Introduced `HtmlViewer` component with enhanced file upload and editor functionalities. - Added `SvgViewer` component for safe SVG markup preview and editing. - Updated constants and routes to include new tools in the development tools list, enhancing user navigation and accessibility. * Update development tools UI and enhance documentation - Modified styles in `[slug]/page.tsx` for the tools panel to improve visual consistency. - Added a new pro tip in `developmentToolsConstant.tsx` regarding the use of `btoa()` with emojis. - Refined step descriptions for the Image Resizer tool to clarify output dimensions and export options. * Add Base64 and Image Conversion Tools - Introduced `Base64ToImageConverter` and `ImageToBase64Converter` components for converting between image files and Base64 strings. - Updated `constants.tsx` to include new tools in the development tools list and adjusted routes accordingly. - Enhanced the `epochConverter` component with additional icons and improved UI for better user experience. - Refined descriptions in `developmentToolsConstant.tsx` to clarify tool functionalities and usage. --------- Co-authored-by: zeel0m Co-authored-by: BetterBugs <135840254+dev-betterbugs@users.noreply.github.com> * Update development tools descriptions and restore SVG Viewer functionality - Enhanced the description for the JavaScript Regex Tester to provide clearer usage details. - Restored the SVG Viewer tool in the development tools list with updated descriptions. - Added new tools: Image to Base64 Converter, Base64 to Image Converter, and HAR File Viewer, with detailed descriptions for each. - Improved overall organization and clarity of the development tools content in constants.tsx. * chore(release): 1.4.0-develop.10 [skip ci] # [1.4.0-develop.10](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.9...v1.4.0-develop.10) (2026-05-22) ### Features * add class-validator dependency and update page styles ([860e1f5](https://github.com/betterbugs/dev-tools/commit/860e1f55497c9ac86a70fadbc6725a5d07f3f26c)) * add Image Resizer and Time Calculator components ([35c3e79](https://github.com/betterbugs/dev-tools/commit/35c3e7901069e60a62e44a9987298945f18f65cc)) * Deploy test (#90) * Update README.md to enhance clarity and organization - Added spacing for improved readability in the Key Features and Available Tools sections. - Refined installation instructions with clearer formatting. - Improved example code formatting for better presentation. - Enhanced the contribution guidelines for better clarity. * Enhance project structure and update dependencies - Updated TypeScript configuration to include new paths and target settings. - Refactored layout components to improve structure and maintainability. - Introduced ClientLayout component for better organization of layout logic. - Updated package dependencies, including major upgrades for React, Next.js, and Ant Design. - Added new deployment scripts for easier integration with Wrangler. - Improved styles and responsiveness across various components. - Enhanced the FAQ collapse component to utilize Ant Design's new item structure. - Added new middleware and configurations for better handling of requests in the application. * Add .npmrc for legacy peer dependencies and update package dependencies - Created a new .npmrc file to set legacy-peer-deps to true. - Updated @monaco-editor/react to version 4.7.0. - Upgraded eslint to version 9 and adjusted related dependencies in package-lock.json. - Enhanced compatibility with newer Node.js versions in various dependencies. * Update README.md for improved punctuation and clarity * Fix wrangler deploy by adding [assets] directory config Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Mohit Mali Co-authored-by: Claude Sonnet 4.6 * Dev tools (#92) * Remove commented-out development tools from constants.tsx for cleaner code and improved maintainability. * Refactor Canonical Link Component to Build Canonical URL Dynamically - Introduced a new function `buildCanonicalPath` to construct the canonical URL based on the current pathname. - Simplified the logic for generating the canonical URL, ensuring it correctly handles the base path and various route scenarios. - Improved code clarity and maintainability by removing redundant URL assignment logic. --------- Co-authored-by: zeel0m --------- Co-authored-by: Harryson <168550932+HarrysonLadines@users.noreply.github.com> Co-authored-by: semantic-release-bot Co-authored-by: Sayak Datta <174126344+datta-sayak@users.noreply.github.com> Co-authored-by: Omkar <182200831+omkarhole@users.noreply.github.com> Co-authored-by: Syed Fahad Co-authored-by: Uday Kiran <132606304+udaykiran243@users.noreply.github.com> Co-authored-by: Madhav Majumdar <161720210+madhav2348@users.noreply.github.com> Co-authored-by: Gaurav Karakoti Co-authored-by: zeel0m Co-authored-by: Aadya Paradkar Co-authored-by: zeel0m <137067026+zeel0m@users.noreply.github.com> Co-authored-by: BetterBugs <135840254+dev-betterbugs@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 --- .gitignore | 3 + .npmrc | 1 + CHANGELOG.md | 8 + README.md | 19 +- app/ClientLayout.tsx | 75 + app/[slug]/PageClient.tsx | 1220 ++ app/[slug]/page.tsx | 1144 +- .../route.ts | 2 + .../collapseFAQComponent.tsx | 30 +- .../comparisonsStyles.module.scss | 52 +- .../epochConverter.tsx | 2 +- .../jsObfuscatorComponent.tsx | 14 +- .../randomDateGenerator.tsx | 2 +- .../productMenuComponent.tsx | 1 + .../resourceMenuComponent.tsx | 1 + .../layout/Header/headerComponent.tsx | 38 +- .../layout/Header/headerStyles.module.scss | 70 +- .../theme/canonicalLink/canonicalLink.tsx | 24 +- app/layout.tsx | 95 +- app/libs/constants.tsx | 32 +- app/libs/developmentToolsConstant.tsx | 885 +- next-env.d.ts | 3 +- next.config.js | 23 +- package-lock.json | 14844 +++++++--------- package.json | 35 +- tsconfig.json | 27 +- wrangler.toml | 6 + 27 files changed, 8678 insertions(+), 9978 deletions(-) create mode 100644 .npmrc create mode 100644 app/ClientLayout.tsx create mode 100644 app/[slug]/PageClient.tsx create mode 100644 wrangler.toml diff --git a/.gitignore b/.gitignore index ac12af4..533853d 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,9 @@ pnpm-lock.yaml .next/ out/ build + +# Wrangler local dev state (auto-generated by wrangler pages dev) +.wrangler/ dist dist-ssr diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..521a9f7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true diff --git a/CHANGELOG.md b/CHANGELOG.md index 580d6ed..750659c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# [1.4.0-develop.10](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.9...v1.4.0-develop.10) (2026-05-22) + + +### Features + +* add class-validator dependency and update page styles ([860e1f5](https://github.com/betterbugs/dev-tools/commit/860e1f55497c9ac86a70fadbc6725a5d07f3f26c)) +* add Image Resizer and Time Calculator components ([35c3e79](https://github.com/betterbugs/dev-tools/commit/35c3e7901069e60a62e44a9987298945f18f65cc)) + # [1.4.0-develop.9](https://github.com/betterbugs/dev-tools/compare/v1.4.0-develop.8...v1.4.0-develop.9) (2026-04-14) ### Features diff --git a/README.md b/README.md index abef891..50d0b48 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ With BetterBugs, debugging stops being guesswork and becomes a shared, reliable source of truth. **Key Features:** + - Real session context from production environments - One-click bug capture with automatic context gathering - Reproducible bug timelines with clear event sequences @@ -92,12 +93,14 @@ BetterBugs Development Tools solves this by providing: ## Available Tools ### Text Tools + - Text case converters (uppercase, lowercase, title case, sentence case) - Text counters (word, character, sentence, line) - Text formatters and manipulators - Lorem Ipsum generator ### Code Tools + - JavaScript minifier and obfuscator - JSON formatter and minifier - HTML to Markdown converter @@ -106,6 +109,7 @@ BetterBugs Development Tools solves this by providing: - CSS formatters and converters ### Data Tools + - JSON validator and formatter - CSV converters and tools - QR Code generator @@ -114,6 +118,7 @@ BetterBugs Development Tools solves this by providing: - URL encoder/decoder ### Color Tools + - Color code converters (HEX, RGB, CMYK) - Color picker and inverter - Random color generator @@ -132,17 +137,20 @@ Browse all available tools at [BetterBugs Development Tools](https://www.betterb ### Installation 1. **Clone the repository** + ```bash git clone https://github.com/betterbugs/dev-tools.git cd dev-tools ``` 2. **Install dependencies** + ```bash npm install ``` 3. **Run the development server** + ```bash npm run dev ``` @@ -190,18 +198,19 @@ dev-tools/ 4. The tool automatically appears on the homepage Example: + ```typescript "use client"; import React, { useState } from "react"; const MyNewTool = () => { const [input, setInput] = useState(""); - + return (
- setInput(e.target.value)} + setInput(e.target.value)} /> {/* Your tool logic */}
@@ -216,6 +225,7 @@ export default MyNewTool; We welcome contributions! Please read our [Contributing Guide](CONTRIBUTING.md) to get started. Key points: + - Follow [Conventional Commits](https://www.conventionalcommits.org) - Target the `develop` branch for feature PRs - See our [Pull Request Template](.github/PULL_REQUEST_TEMPLATE.md) for guidance @@ -232,6 +242,7 @@ Found a security vulnerability? Please email us at dev@betterbugs.io instead of ## Reporting Issues Found a bug? Open an issue on [GitHub Issues](https://github.com/betterbugs/dev-tools/issues) with: + - Clear description of the problem - Steps to reproduce - Expected vs actual behavior diff --git a/app/ClientLayout.tsx b/app/ClientLayout.tsx new file mode 100644 index 0000000..dfec56d --- /dev/null +++ b/app/ClientLayout.tsx @@ -0,0 +1,75 @@ +'use client'; +import { Suspense, useContext } from 'react'; +import { CookiesProvider } from 'react-cookie'; +import { + LayoutContext, + LayoutContextModel, + LayoutContextProvider, +} from './contexts/layoutContexts'; +import { ThemeProvider } from './contexts/themeContext'; +import HeaderComponent from './components/layout/Header/headerComponent'; +import FooterComponent from './components/layout/footer/footerComponent'; +import CanonicalLink from './components/theme/canonicalLink/canonicalLink'; +import { useMediaQuery } from 'react-responsive'; +import dynamic from 'next/dynamic'; + +const AnimatedCursor = dynamic(() => import('react-animated-cursor'), { + ssr: false, +}); + +const InnerContent = ({ children }: { children: React.ReactNode }) => { + const { isClient }: LayoutContextModel = useContext(LayoutContext); + const isDesktopOrLaptop = useMediaQuery({ query: '(min-width: 1024px)' }); + + return ( +
+ {isClient && isDesktopOrLaptop && ( + + )} + + + + {children} + +
+ ); +}; + +const ClientLayout = ({ children }: { children: React.ReactNode }) => { + return ( + + + + + + {children} + + + + + ); +}; + +export default ClientLayout; diff --git a/app/[slug]/PageClient.tsx b/app/[slug]/PageClient.tsx new file mode 100644 index 0000000..50187c9 --- /dev/null +++ b/app/[slug]/PageClient.tsx @@ -0,0 +1,1220 @@ +'use client'; +import React, { useEffect, useState } from 'react'; +import { DEVELOPMENTTOOLS } from '@/app/libs/developmentToolsConstant'; +import Link from 'next/link'; +import { Button } from 'antd'; +import Image from 'next/image'; +import StarGardientIcon from '@/app/components/theme/Icon/starGradientIcon'; +import { + developmentToolsRoutes, + Extension_URL, + integrationTools, +} from '@/app/libs/constants'; +import PlayIcon from '@/app/components/theme/Icon/playIcon'; +import LogsGradientIcon from '@/app/components/theme/Icon/logsGradientIcon'; +import ShareGradientIcon from '@/app/components/theme/Icon/shareGradientIcon'; +import PowerCircleIcon from '@/app/components/theme/Icon/powerCircleIcon'; +import ComparisonsStyles from '../components/comparisonsComponent/comparisonsStyles.module.scss'; +import DevelopmentToolsStyles from '../developmentToolsStyles.module.scss'; +import { usePathname } from 'next/navigation'; +import RecorderGradientIcon from '@/app/components/theme/Icon/recorderGradientIcon'; +import SEOComponent from '@/app/components/theme/SEOComponent/SEOComponent'; +import { detectBrowser } from '@/app/libs/helpers'; +import EdgeIcon from '@/app/components/theme/Icon/edgeIcon'; +import { useTheme } from '@/app/contexts/themeContext'; + +const PageClient = ({ slug }: { slug: string }) => { + const [browser, setBrowser] = useState('chrome'); + const { isLightTheme } = useTheme(); + const logoSrc = isLightTheme + ? '/images/bb-logo-light.svg' + : '/images/bb-logo.svg'; + + useEffect(() => { + setBrowser(detectBrowser()); + }, []); + const toolsData = DEVELOPMENTTOOLS[slug]; + const { + hero_section, + development_tools_list, + development_tools_about_details, + development_tools_what, + development_tools_user_agent_info, + development_tools_steps_guide, + development_tools_how_use, + development_tools_Comparison, + development_tool_example, + meta_data, + } = toolsData; + const pathname = usePathname(); + + const currentTool = developmentToolsRoutes.find( + (tool: any) => tool.path === pathname + ); + + return ( + <> + +
+
+ {/*Hero cta section */} +
+
+
+ {/* Left Section */} +
+ BetterBugs Logo +
+

+ The essential AI{' '} + companion every QA needs +

+ + + +
+ +

+ Swiftly document and share bugs like never before +

+
+ + + +
+

+ Free Forever. No Credit Card Required. +

+
+ + {/* Right Section */} +
+ {/* Features Section */} +
+
+ +

+ Use AI to + reproduce and fix bugs +

+
+
+ +

+ + Screen Recording + {' '} + with{' '} + + Rewind (Upto 2-min) + +

+
+
+ +

+ Capture{' '} + + {' '} + backend logs + + with every bug report +

+
+
+ +

+ Assign bugs and{' '} + share at + single click +

+
+
+ +
+
+
+
+
+
+ +
+ {/* Heading section */} + {hero_section && ( +
+
+

+ {hero_section?.title} +

+

+ {hero_section?.description + ?.split('BetterBugs.io') + .map((part: any, index: any, arr: any) => ( + + {part} + {index !== arr.length - 1 && ( + + BetterBugs.io + + )} + + ))} +

+
+
+ )} + + {/* Integrated Tool section */} + {currentTool ? currentTool?.component : null} + + {/* Tool description section */} +
+
+ {/* Tools Panel - 20% width, fixed */} + {development_tools_list?.length > 0 && ( +
+
+
+

+ Other Tools +

+
+ {development_tools_list?.map((tool: any, index: any) => ( + +
+ {tool?.tool} +
+ + ))} +
+
+ )} + + {/* Q&A Panel - 80% width, scrollable */} +
+ {/* about section */} +
+ {development_tools_about_details?.about_title && ( +

+ {development_tools_about_details?.about_title} +

+ )} + {development_tools_about_details?.about_description?.map( + (desc: any, index: number) => { + // Check if this description item has a list + if (desc?.list && Array.isArray(desc?.list)) { + return ( +
    + {desc?.list?.map( + (listItem: any, listIndex: number) => ( +
  • + {listItem?.title} + {listItem?.description && ( + + {listItem?.description} + + )} +
  • + ) + )} +
+ ); + } + + // Check if this description item has examples + if (desc?.example && Array.isArray(desc?.example)) { + return ( +
+ {/* Render description if it exists */} + {desc?.description && ( +

+ {desc.description} +

+ )} + {/* Render examples */} + {desc.example.map( + (exampleItem: any, exampleIndex: number) => { + const isExampleHeading = + exampleItem?.example_input?.startsWith( + 'Example' + ); + const isInputOrOutput = + exampleItem?.example_input === 'Input' || + exampleItem?.example_input === 'Output'; + const isStringOutput = + typeof exampleItem?.example_output === + 'string'; + const isArrayOutput = Array.isArray( + exampleItem?.example_output + ); + + return ( +
0 ? 'mt-3' : ''} + > + {isExampleHeading && ( + <> +

+ {exampleItem.example_input} +

+ {isStringOutput && ( +

+ {exampleItem.example_output} +

+ )} + + )} + {isInputOrOutput && ( + <> +

+ {exampleItem.example_input} +

+ {isArrayOutput && ( +
+ {exampleItem.example_output.map( + ( + outputItem: any, + outputIndex: number + ) => ( +

+ {outputItem?.value} +

+ ) + )} +
+ )} + + )} +
+ ); + } + )} +
+ ); + } + + // Handle regular description text + const descriptions = desc?.description || ''; + const splitDescriptions = + descriptions.split(/((['"]).*?\2)/); // Split quoted and unquoted text + + return ( +

+ {splitDescriptions.map( + (text: any, subIndex: any) => { + const isQuoted = + typeof text === 'string' && + /^(['"]).*\1$/.test(text); + const containsBetterBugs = + text.includes('BetterBugs.io'); + if (containsBetterBugs) { + const parts = text.split('BetterBugs.io'); + return ( + + + {parts[0]} + + + BetterBugs.io + + + {parts[1]} + + + ); + } + + return ( + + {text} + + ); + } + )} +

+ ); + } + )} + + {development_tools_about_details?.placeholder && ( +
    + {development_tools_about_details?.placeholder?.map( + (placeholder: any, index: any) => ( +
  • + + {placeholder?.title} + +
  • + ) + )} +
+ )} +
+ + {/* user agent info section */} + {development_tools_user_agent_info && ( +
+ {development_tools_user_agent_info?.info_title && ( +

+ {development_tools_user_agent_info?.info_title} +

+ )} + {development_tools_user_agent_info?.intro_text && ( +

+ {development_tools_user_agent_info?.intro_text} +

+ )} + {development_tools_user_agent_info?.example_string && ( +

+ {development_tools_user_agent_info?.example_string} +

+ )} + {development_tools_user_agent_info?.example_string_description && ( +

+ { + development_tools_user_agent_info?.example_string_description + } +

+ )} + {development_tools_user_agent_info?.info_items && ( +
+
    + {development_tools_user_agent_info?.info_items?.map( + (item: any, index: number) => ( +
  • + + {item?.part}{' '} + + + {item?.description} + +
  • + ) + )} +
+
+ )} +
+ )} + + {/* step-by-step guide */} +
+ {development_tools_steps_guide?.guide_title && ( + <> +
+ {development_tools_steps_guide?.guide_title} +
+

+ {development_tools_steps_guide?.guide_description + ?.split(/((['"]).*?\2)/g) + ?.map((parts: any, i: any) => { + const isQuoted = + typeof parts === 'string' && + /^(['"]).*\1$/.test(parts); + return isQuoted ? ( + + {parts} + + ) : ( + + {parts} + + ); + })} +

+ + )} + {development_tools_steps_guide?.steps?.length > 0 && ( +
+ {development_tools_steps_guide?.steps?.map( + (guide: any, index: any) => { + const description = guide?.step_description; + const description2 = guide?.step_description2; + + // Split quoted and unquoted text + const parts = description?.split(/((['"]).*?\2)/); + const desParts = + description2?.split(/((['"]).*?\2)/); + + return ( +
+ {/* Primary Flex Layout for Step Key, Title, and Description */} +
+ + {guide?.step_key} + + + {guide?.step_title} + +
+ + {/* Step descriptions (below title) */} + {description && ( +
+ {parts?.map((part: any, i: any) => { + const isQuoted = + typeof part === 'string' && + /^(['"]).*\1$/.test(part); + return isQuoted ? ( + + {part} + + ) : ( + + {part} + + ); + })} +
+ )} + + {/* Step Description2 on a New Line, Only If Present */} + {description2 && desParts?.length > 0 && ( +
+ {desParts?.map((part: any, i: any) => { + const isQuoted = + typeof part === 'string' && + /^(['"]).*\1$/.test(part); + return isQuoted ? ( + + {part} + + ) : ( + + {part} + + ); + })} +
+ )} + + {guide?.steps_points?.length > 0 && ( +
    + {guide?.steps_points?.map( + (p: any, index: number) => ( +
  • + {p?.steps_points_title && ( + + {p?.steps_points_title} + + )} + {p?.steps_points_description && ( +

    + {p?.steps_points_description + ?.split(/((['"]).*?\2)/) + .map( + (part: string, i: number) => + typeof part === 'string' && + /^(['"]).*\1$/.test( + part + ) ? ( + + {part} + + ) : ( + + {part + .split( + /(\/\/.*?\/\/)/ + ) + .map( + ( + sub: string, + j: number + ) => + sub.startsWith( + '//' + ) && + sub.endsWith( + '//' + ) ? ( + + {sub.slice( + 2, + -2 + )} + + ) : ( + sub + ) + )} + + ) + )} +

    + )} + {Array.isArray(p?.steps_subpoint) && + p?.steps_subpoint?.length > 0 && ( +
      + {p?.steps_subpoint?.map( + ( + sub_p: any, + subIndex: number + ) => ( +
    • + {sub_p?.title && ( + + {sub_p?.title} + + )} + {sub_p?.description && ( + + {sub_p?.description + ?.split( + /((['"]).*?\2)/ + ) + .map( + ( + part: string, + i: number + ) => + typeof part === + 'string' && + /^(['"]).*\1$/.test( + part + ) ? ( + + {part} + + ) : ( + + {part + .split( + /(\/\/.*?\/\/)/ + ) + .map( + ( + sub: string, + j: number + ) => + sub.startsWith( + '//' + ) && + sub.endsWith( + '//' + ) ? ( + + {sub.slice( + 2, + -2 + )} + + ) : ( + sub + ) + )} + + ) + )} + + )} +
    • + ) + )} +
    + )} +
  • + ) + )} +
+ )} +
+ ); + } + )} +
+ )} +
+ + {/* example section */} + {development_tool_example && ( +
+ {development_tool_example?.example_title && ( +

+ {development_tool_example?.example_title} +

+ )} + {development_tool_example?.example_description && ( +

+ {development_tool_example?.example_description} +

+ )} + + {development_tool_example?.example_input && ( +
+ {development_tool_example?.example_input?.title && ( +

+ {development_tool_example?.example_input?.title} +

+ )} + {development_tool_example?.example_input + ?.json_data && ( +
+                              
+                                {
+                                  development_tool_example?.example_input
+                                    ?.json_data
+                                }
+                              
+                            
+ )} +
+ )} + + {development_tool_example?.example_outputs && ( +
+ {development_tool_example?.example_outputs?.intro && ( +

+ {development_tool_example?.example_outputs?.intro} +

+ )} + {development_tool_example?.example_outputs?.outputs?.map( + (output: any, index: number) => ( +
+ {output?.mode && ( +

+ {output?.mode} +

+ )} + {output?.title && ( +

+ {output?.title} +

+ )} + {output?.content && ( +
+                                    
+                                      {output?.content}
+                                    
+                                  
+ )} + {output?.note && ( +

+ {output?.note} +

+ )} +
+ ) + )} +
+ )} + + {/* JavaScript example section (optional) */} + {development_tool_example?.javascript_example && ( +
+ {development_tool_example?.javascript_example + ?.title && ( +
+ { + development_tool_example?.javascript_example + ?.title + } +
+ )} + {development_tool_example?.javascript_example + ?.description && ( +

+ { + development_tool_example?.javascript_example + ?.description + } +

+ )} + + {development_tool_example?.javascript_example?.methods + ?.length > 0 && ( +
+
    + {development_tool_example?.javascript_example?.methods?.map( + (method: any, index: number) => ( +
  • + {method?.name && ( + + {method?.name}{' '} + + )} + {method?.description && ( + + {method?.description} + + )} +
  • + ) + )} +
+
+ )} + + {development_tool_example?.javascript_example + ?.examples?.length > 0 && ( +
+ {development_tool_example?.javascript_example?.examples?.map( + (example: any, index: number) => ( +
+ {example?.title && ( +

+ {example?.title} +

+ )} + {example?.code && ( +
+                                        
+                                          {example?.code}
+                                        
+                                      
+ )} +
+ ) + )} +
+ )} + + {development_tool_example?.javascript_example + ?.note && ( +

+ { + development_tool_example?.javascript_example + ?.note + } +

+ )} +
+ )} +
+ )} + + {/* what section */} + {development_tools_what && ( +
+ {development_tools_what?.about_title && ( +

+ {development_tools_what?.about_title} +

+ )} + {development_tools_what?.what_description?.map( + (desc: any, index: number) => { + const descriptions = desc?.descriptions; + const splitDescriptions = + descriptions.split(/((['"]).*?\2)/); // Split quoted and unquoted text + + return ( +

+ {splitDescriptions.map( + (text: any, subIndex: any) => { + const isQuoted = + typeof text === 'string' && + /^(['"]).*\1$/.test(text); + + return ( + + {text} + + ); + } + )} +

+ ); + } + )} +
+ )} + + {/* how to use */} +
+ {development_tools_how_use?.how_use_title && ( + <> +
+ {development_tools_how_use?.how_use_title} +
+

+ {development_tools_how_use?.how_use_description} +

+ + )} + {development_tools_how_use?.point?.length > 0 && ( +
+
    + {development_tools_how_use?.point?.map( + (how: any, index: any) => + how?.heading ? ( +

    + {how?.heading} +

    + ) : ( +
  • + <> + + {how?.title} + + + {how?.description} + + +
  • + ) + )} +
+
+ )} +
+ + {/* Comparison section */} + {development_tools_Comparison && ( +
+ {development_tools_Comparison?.title && ( +

+ {development_tools_Comparison?.title} +

+ )} + {Array.isArray( + development_tools_Comparison?.description + ) && + development_tools_Comparison?.description.map( + (d: any, index: any) => ( +

+ {d?.desc} +

+ ) + )} +
+ )} +
+
+
+ + {/* cta section */} +
+
+
+ {/* Left Section */} +
+ BetterBugs Logo +
+

+ The essential AI{' '} + companion every QA needs +

+ + + +
+ +

+ Swiftly document and share bugs like never before +

+
+ + + + + + +
+

+ Free Forever. No Credit Card Required. +

+
+ + {/* Right Section */} +
+
+ + {/* Features Section */} +
+
+ +

+ Use AI{' '} + to reproduce and fix bugs +

+
+
+ +

+ + Screen Recording + {' '} + with{' '} + + Rewind (Upto 2-min) + +

+
+
+ +

+ Capture{' '} + + {' '} + backend logs + + with every bug report +

+
+
+ +

+ Assign bugs and{' '} + share at + single click +

+
+
+ +
+
+
+ + {/* Integrations Section */} +
+

+ Integrations +

+

+ Two-way sync with +
popular tools +

+
+ {integrationTools?.map((tool, index) => ( + +
+ + {tool?.icon} + +

+ {tool?.name} +

+
+ + ))} +
+
+
+
+
+
+
+
+ + ); +}; + +export default PageClient; diff --git a/app/[slug]/page.tsx b/app/[slug]/page.tsx index e469e6c..8f08f40 100644 --- a/app/[slug]/page.tsx +++ b/app/[slug]/page.tsx @@ -1,1143 +1,13 @@ -'use client'; -import React, { useEffect, useState } from 'react'; import { DEVELOPMENTTOOLS } from '@/app/libs/developmentToolsConstant'; -import Link from 'next/link'; -import { Button } from 'antd'; -import Image from 'next/image'; -import StarGardientIcon from '@/app/components/theme/Icon/starGradientIcon'; -import { - developmentToolsRoutes, - Extension_URL, - integrationTools, -} from '@/app/libs/constants'; -import PlayIcon from '@/app/components/theme/Icon/playIcon'; -import LogsGradientIcon from '@/app/components/theme/Icon/logsGradientIcon'; -import ShareGradientIcon from '@/app/components/theme/Icon/shareGradientIcon'; -import PowerCircleIcon from '@/app/components/theme/Icon/powerCircleIcon'; -import ComparisonsStyles from '../components/comparisonsComponent/comparisonsStyles.module.scss'; -import DevelopmentToolsStyles from '../developmentToolsStyles.module.scss'; -import { usePathname } from 'next/navigation'; -import RecorderGradientIcon from '@/app/components/theme/Icon/recorderGradientIcon'; -import SEOComponent from '@/app/components/theme/SEOComponent/SEOComponent'; -import { detectBrowser } from '@/app/libs/helpers'; -import EdgeIcon from '@/app/components/theme/Icon/edgeIcon'; -import { useTheme } from '@/app/contexts/themeContext'; +import PageClient from './PageClient'; -const Page = ({ params: { slug } }: { params: { slug: string } }) => { - const [browser, setBrowser] = useState('chrome'); - const { isLightTheme } = useTheme(); - const logoSrc = isLightTheme - ? '/images/bb-logo-light.svg' - : '/images/bb-logo.svg'; +export async function generateStaticParams() { + return Object.keys(DEVELOPMENTTOOLS).map(slug => ({ slug })); +} - useEffect(() => { - setBrowser(detectBrowser()); - }, []); - const toolsData = DEVELOPMENTTOOLS[slug]; - const { - hero_section, - development_tools_list, - development_tools_about_details, - development_tools_what, - development_tools_user_agent_info, - development_tools_steps_guide, - development_tools_how_use, - development_tools_Comparison, - development_tool_example, - meta_data, - } = toolsData; - const pathname = usePathname(); - - const currentTool = developmentToolsRoutes.find( - (tool: any) => tool.path === pathname - ); - - return ( - <> - -
-
- {/*Hero cta section */} -
-
-
- {/* Left Section */} -
- BetterBugs Logo -
-

- The essential AI{' '} - companion every QA needs -

- - - -
- -

- Swiftly document and share bugs like never before -

-
- - - -
-

- Free Forever. No Credit Card Required. -

-
- - {/* Right Section */} -
- {/* Features Section */} -
-
- -

- Use AI to - reproduce and fix bugs -

-
-
- -

- - Screen Recording - {' '} - with{' '} - - Rewind (Upto 2-min) - -

-
-
- -

- Capture{' '} - - {' '} - backend logs - - with every bug report -

-
-
- -

- Assign bugs and{' '} - share at - single click -

-
-
- -
-
-
-
-
-
- -
- {/* Heading section */} - {hero_section && ( -
-
-

- {hero_section?.title} -

-

- {hero_section?.description - ?.split('BetterBugs.io') - .map((part: any, index: any, arr: any) => ( - - {part} - {index !== arr.length - 1 && ( - - BetterBugs.io - - )} - - ))} -

-
-
- )} - - {/* Integrated Tool section */} - {currentTool ? currentTool?.component : null} - - {/* Tool description section */} -
-
- {/* Tools Panel - 20% width, fixed */} - {development_tools_list?.length > 0 && ( -
-
-
-

- Other Tools -

-
- {development_tools_list?.map((tool: any, index: any) => ( - -
- {tool?.tool} -
- - ))} -
-
- )} - - {/* Q&A Panel - 80% width, scrollable */} -
- {/* about section */} -
- {development_tools_about_details?.about_title && ( -

- {development_tools_about_details?.about_title} -

- )} - {development_tools_about_details?.about_description?.map( - (desc: any, index: number) => { - // Check if this description item has a list - if (desc?.list && Array.isArray(desc?.list)) { - return ( -
    - {desc?.list?.map( - (listItem: any, listIndex: number) => ( -
  • - {listItem?.title} - {listItem?.description && ( - - {listItem?.description} - - )} -
  • - ) - )} -
- ); - } - - // Check if this description item has examples - if (desc?.example && Array.isArray(desc?.example)) { - return ( -
- {/* Render description if it exists */} - {desc?.description && ( -

- {desc.description} -

- )} - {/* Render examples */} - {desc.example.map( - (exampleItem: any, exampleIndex: number) => { - const isExampleHeading = - exampleItem?.example_input?.startsWith( - 'Example' - ); - const isInputOrOutput = - exampleItem?.example_input === 'Input' || - exampleItem?.example_input === 'Output'; - const isStringOutput = - typeof exampleItem?.example_output === - 'string'; - const isArrayOutput = Array.isArray( - exampleItem?.example_output - ); - - return ( -
0 ? 'mt-3' : ''} - > - {isExampleHeading && ( - <> -

- {exampleItem.example_input} -

- {isStringOutput && ( -

- {exampleItem.example_output} -

- )} - - )} - {isInputOrOutput && ( - <> -

- {exampleItem.example_input} -

- {isArrayOutput && ( -
- {exampleItem.example_output.map( - ( - outputItem: any, - outputIndex: number - ) => ( -

- {outputItem?.value} -

- ) - )} -
- )} - - )} -
- ); - } - )} -
- ); - } - - // Handle regular description text - const descriptions = desc?.description || ""; - const splitDescriptions = descriptions.split(/((['"]).*?\2)/); // Split quoted and unquoted text - - return ( -

- {splitDescriptions.map( - (text: any, subIndex: any) => { - const isQuoted = - typeof text === "string" && /^(['"]).*\1$/.test(text); - const containsBetterBugs = - text.includes('BetterBugs.io'); - - if (containsBetterBugs) { - // Split the text around 'BetterBugs.io' to wrap it in a link - const parts = text.split('BetterBugs.io'); - return ( - - - {parts[0]} - - - BetterBugs.io - - - {parts[1]} - - - ); - } - - return ( - - {text} - - ); - } - )} -

- ); - } - )} - - {development_tools_about_details?.placeholder && ( -
    - {development_tools_about_details?.placeholder?.map( - (placeholder: any, index: any) => ( -
  • - - {placeholder?.title} - -
  • - ) - )} -
- )} -
- - {/* user agent info section */} - {development_tools_user_agent_info && ( -
- {development_tools_user_agent_info?.info_title && ( -

- {development_tools_user_agent_info?.info_title} -

- )} - {development_tools_user_agent_info?.intro_text && ( -

- {development_tools_user_agent_info?.intro_text} -

- )} - {development_tools_user_agent_info?.example_string && ( -

- {development_tools_user_agent_info?.example_string} -

- )} - {development_tools_user_agent_info?.example_string_description && ( -

- {development_tools_user_agent_info?.example_string_description} -

- )} - {development_tools_user_agent_info?.info_items && ( -
-
    - {development_tools_user_agent_info?.info_items?.map( - (item: any, index: number) => ( -
  • - - {item?.part}{' '} - - - {item?.description} - -
  • - ) - )} -
-
- )} -
- )} - - {/* step-by-step guide */} -
- {development_tools_steps_guide?.guide_title && ( - <> -
- {development_tools_steps_guide?.guide_title} -
-

- {development_tools_steps_guide?.guide_description - ?.split(/((['"]).*?\2)/g) - ?.map((parts: any, i: any) => { - const isQuoted = - typeof parts === "string" && - /^(['"]).*\1$/.test(parts); - return isQuoted ? ( - - {parts} - - ) : ( - - {parts} - - ); - })} -

- - )} - {development_tools_steps_guide?.steps?.length > 0 && ( -
- {development_tools_steps_guide?.steps?.map( - (guide: any, index: any) => { - const description = guide?.step_description; - const description2 = guide?.step_description2; - - // Split quoted and unquoted text - const parts = description?.split(/((['"]).*?\2)/); - const desParts = description2?.split(/((['"]).*?\2)/); - - return ( -
- {/* Primary Flex Layout for Step Key, Title, and Description */} -
- - {guide?.step_key} - - - {guide?.step_title} - -
- - {/* Step descriptions (below title) */} - {description && ( -
- {parts?.map((part: any, i: any) => { - const isQuoted = - typeof part === "string" && - /^(['"]).*\1$/.test(part); - return isQuoted ? ( - - {part} - - ) : ( - - {part} - - ); - })} -
- )} - - {/* Step Description2 on a New Line, Only If Present */} - {description2 && desParts?.length > 0 && ( -
- {desParts?.map((part: any, i: any) => { - const isQuoted = - typeof part === "string" && - /^(['"]).*\1$/.test(part); - return isQuoted ? ( - - {part} - - ) : ( - - {part} - - ); - })} -
- )} - - {guide?.steps_points?.length > 0 && ( -
    - {guide?.steps_points?.map((p: any, index: number) => ( -
  • - {p?.steps_points_title && ( - - {p?.steps_points_title} - - )} - {p?.steps_points_description && ( -

    - {p?.steps_points_description - ?.split(/((['"]).*?\2)/) - .map((part: string, i: number) => - typeof part === "string" && - /^(['"]).*\1$/.test(part) ? ( - - {part} - - ) : ( - - {part - .split(/(\/\/.*?\/\/)/) - .map((sub: string, j: number) => - sub.startsWith("//") && sub.endsWith("//") ? ( - - {sub.slice(2, -2)} - - ) : ( - sub - ) - )} - - ) - )} -

    - )} - {Array.isArray(p?.steps_subpoint) && p?.steps_subpoint?.length > 0 && ( -
      - {p?.steps_subpoint?.map((sub_p: any, subIndex: number) => ( -
    • - {sub_p?.title && ( - - {sub_p?.title} - - )} - {sub_p?.description && ( - - {sub_p?.description - ?.split(/((['"]).*?\2)/) - .map((part: string, i: number) => - typeof part === "string" && - /^(['"]).*\1$/.test(part) ? ( - - {part} - - ) : ( - - {part - .split(/(\/\/.*?\/\/)/) - .map((sub: string, j: number) => - sub.startsWith("//") && sub.endsWith("//") ? ( - - {sub.slice(2, -2)} - - ) : ( - sub - ) - )} - - ) - )} - - )} -
    • - ))} -
    - )} -
  • - ))} -
- )} -
- ); - } - )} -
- )} -
- - {/* example section */} - {development_tool_example && ( -
- {development_tool_example?.example_title && ( -

- {development_tool_example?.example_title} -

- )} - {development_tool_example?.example_description && ( -

- {development_tool_example?.example_description} -

- )} - - {development_tool_example?.example_input && ( -
- {development_tool_example?.example_input?.title && ( -

- {development_tool_example?.example_input?.title} -

- )} - {development_tool_example?.example_input - ?.json_data && ( -
-                              
-                                {
-                                  development_tool_example?.example_input
-                                    ?.json_data
-                                }
-                              
-                            
- )} -
- )} - - {development_tool_example?.example_outputs && ( -
- {development_tool_example?.example_outputs?.intro && ( -

- {development_tool_example?.example_outputs?.intro} -

- )} - {development_tool_example?.example_outputs?.outputs?.map( - (output: any, index: number) => ( -
- {output?.mode && ( -

- {output?.mode} -

- )} - {output?.title && ( -

- {output?.title} -

- )} - {output?.content && ( -
-                                    
-                                      {output?.content}
-                                    
-                                  
- )} - {output?.note && ( -

- {output?.note} -

- )} -
- ) - )} -
- )} - - {/* JavaScript example section (optional) */} - {development_tool_example?.javascript_example && ( -
- {development_tool_example?.javascript_example - ?.title && ( -
- { - development_tool_example?.javascript_example - ?.title - } -
- )} - {development_tool_example?.javascript_example - ?.description && ( -

- { - development_tool_example?.javascript_example - ?.description - } -

- )} - - {development_tool_example?.javascript_example?.methods - ?.length > 0 && ( -
-
    - {development_tool_example?.javascript_example?.methods?.map( - (method: any, index: number) => ( -
  • - {method?.name && ( - - {method?.name}{' '} - - )} - {method?.description && ( - - {method?.description} - - )} -
  • - ) - )} -
-
- )} - - {development_tool_example?.javascript_example - ?.examples?.length > 0 && ( -
- {development_tool_example?.javascript_example?.examples?.map( - (example: any, index: number) => ( -
- {example?.title && ( -

- {example?.title} -

- )} - {example?.code && ( -
-                                        
-                                          {example?.code}
-                                        
-                                      
- )} -
- ) - )} -
- )} - - {development_tool_example?.javascript_example - ?.note && ( -

- { - development_tool_example?.javascript_example - ?.note - } -

- )} -
- )} -
- )} - - {/* what section */} - {development_tools_what && ( -
- {development_tools_what?.about_title && ( -

- {development_tools_what?.about_title} -

- )} - {development_tools_what?.what_description?.map( - (desc: any, index: number) => { - const descriptions = desc?.descriptions; - const splitDescriptions = - descriptions.split(/((['"]).*?\2)/); // Split quoted and unquoted text - - return ( -

- {splitDescriptions.map( - (text: any, subIndex: any) => { - const isQuoted = - typeof text === "string" && - /^(['"]).*\1$/.test(text); - - return ( - - {text} - - ); - } - )} -

- ); - } - )} -
- )} - - {/* how to use */} -
- {development_tools_how_use?.how_use_title && ( - <> -
- {development_tools_how_use?.how_use_title} -
-

- {development_tools_how_use?.how_use_description} -

- - )} - {development_tools_how_use?.point?.length > 0 && ( -
-
    - {development_tools_how_use?.point?.map( - (how: any, index: any) => - how?.heading ? ( -

    - {how?.heading} -

    - ) : ( -
  • - <> - - {how?.title} - - - {how?.description} - - -
  • - ) - )} -
-
- )} -
- - {/* Comparison section */} - {development_tools_Comparison && ( -
- {development_tools_Comparison?.title && ( -

- {development_tools_Comparison?.title} -

- )} - {Array.isArray( - development_tools_Comparison?.description - ) && - development_tools_Comparison?.description.map( - (d: any, index: any) => ( -

- {d?.desc} -

- ) - )} -
- )} -
-
-
- - {/* cta section */} -
-
-
- {/* Left Section */} -
- BetterBugs Logo -
-

- The essential AI{' '} - companion every QA needs -

- - - -
- -

- Swiftly document and share bugs like never before -

-
- - - - - - -
-

- Free Forever. No Credit Card Required. -

-
- - {/* Right Section */} -
-
- - {/* Features Section */} -
-
- -

- Use AI{' '} - to reproduce and fix bugs -

-
-
- -

- - Screen Recording - {' '} - with{' '} - - Rewind (Upto 2-min) - -

-
-
- -

- Capture{' '} - - {' '} - backend logs - - with every bug report -

-
-
- -

- Assign bugs and{' '} - share at - single click -

-
-
- -
-
-
- - {/* Integrations Section */} -
-

- Integrations -

-

- Two-way sync with -
popular tools -

-
- {integrationTools?.map((tool, index) => ( - -
- - {tool?.icon} - -

- {tool?.name} -

-
- - ))} -
-
-
-
-
-
-
-
- - ); +const Page = async ({ params }: { params: Promise<{ slug: string }> }) => { + const { slug } = await params; + return ; }; export default Page; diff --git a/app/api/development-tools-category-content/route.ts b/app/api/development-tools-category-content/route.ts index b23dd61..604ce0a 100644 --- a/app/api/development-tools-category-content/route.ts +++ b/app/api/development-tools-category-content/route.ts @@ -1,6 +1,8 @@ import { NextResponse } from 'next/server'; import { developmentToolsCategoryContent } from '@/app/libs/constants'; +export const dynamic = 'force-static'; + export async function GET() { console.log( 'developmentToolsCategoryContent', diff --git a/app/components/collapseFAQComponent/collapseFAQComponent.tsx b/app/components/collapseFAQComponent/collapseFAQComponent.tsx index 7f16a54..3c4026e 100644 --- a/app/components/collapseFAQComponent/collapseFAQComponent.tsx +++ b/app/components/collapseFAQComponent/collapseFAQComponent.tsx @@ -9,24 +9,26 @@ export interface CollapseFAQComponentProps { const CollapseFAQComponent = (props: CollapseFAQComponentProps) => { const { FAQs } = props; - const { Panel } = Collapse; return (
- - {FAQs?.map((faq: any) => ( - - {faq?.title} -
- } - key={faq?.key} - > + ({ + key: faq?.key, + label: ( +
+ {faq?.title} +
+ ), + children: (

{faq?.des}

- - ))} -
+ ), + }))} + /> ); }; diff --git a/app/components/comparisonsComponent/comparisonsStyles.module.scss b/app/components/comparisonsComponent/comparisonsStyles.module.scss index 7aa1652..4a0f77e 100644 --- a/app/components/comparisonsComponent/comparisonsStyles.module.scss +++ b/app/components/comparisonsComponent/comparisonsStyles.module.scss @@ -9,16 +9,6 @@ height: 100%; } -// .testimonialCard { -// margin-top: 40px; -// background: linear-gradient(180deg, #000000 0%, rgba(102, 102, 102, 0) 100%); -// border-top: 1px solid #00da92; -// border-right: 1px solid #00da92; -// border-left: 1px solid #00da92; -// border-bottom: 0; -// border-radius: 20px; -// } - .ctaCardGridBg { background: linear-gradient( 180deg, @@ -34,34 +24,32 @@ inset 0 1px 0 rgba(255, 255, 255, 0.9); } -.collapse { - :global(.ant-collapse) { - background-color: transparent !important; - - :global(.ant-collapse-expand-icon) { - color: white !important; - order: 2; - } +.collapse :global(.ant-collapse) { + background-color: transparent !important; +} - @media (min-width: 1024px) { - :global(.ant-collapse-header) { - padding: 0px 0px 16px 0px !important; - } - } +.collapse :global(.ant-collapse .ant-collapse-expand-icon) { + color: white !important; + order: 2; +} - @media (max-width: 564px) { - :global(.ant-collapse-header) { - padding: 16px 0px 16px 0px !important; - align-items: center !important; - } - } +@media (min-width: 1024px) { + .collapse :global(.ant-collapse .ant-collapse-header) { + padding: 0px 0px 16px 0px !important; + } +} - :global(.ant-collapse-content-box) { - padding: 0px 0px 20px 0px !important; - } +@media (max-width: 564px) { + .collapse :global(.ant-collapse .ant-collapse-header) { + padding: 16px 0px 16px 0px !important; + align-items: center !important; } } +.collapse :global(.ant-collapse .ant-collapse-content-box) { + padding: 0px 0px 20px 0px !important; +} + .borderBottom { &:last-child { border-bottom: 5px solid #00da92; diff --git a/app/components/developmentToolsComponent/epochConverter.tsx b/app/components/developmentToolsComponent/epochConverter.tsx index dfc9017..af8d025 100644 --- a/app/components/developmentToolsComponent/epochConverter.tsx +++ b/app/components/developmentToolsComponent/epochConverter.tsx @@ -97,7 +97,7 @@ const EpochConverter = () => {
{ const [inputCode, setInputCode] = useState(""); const [outputCode, setOutputCode] = useState(""); - const handleObfuscate = () => { + const handleObfuscate = async () => { if (!inputCode.trim()) { toast.error("Error: Cannot obfuscate an empty file!"); - return; // Don't proceed with obfuscation if the code is empty + return; } try { + const { default: JavaScriptObfuscator } = await import("javascript-obfuscator"); const obfuscatedCode = JavaScriptObfuscator.obfuscate(inputCode, { compact: true, controlFlowFlattening: true, }).getObfuscatedCode(); setOutputCode(obfuscatedCode); } catch (error) { - setOutputCode(""); // Clear the output on error - toast.error(`Error obfuscating code: ${(error as Error).message}`); // Set the obfuscation error message + setOutputCode(""); + toast.error(`Error obfuscating code: ${(error as Error).message}`); } }; diff --git a/app/components/developmentToolsComponent/randomDateGenerator.tsx b/app/components/developmentToolsComponent/randomDateGenerator.tsx index 6438dac..bdc8ef8 100644 --- a/app/components/developmentToolsComponent/randomDateGenerator.tsx +++ b/app/components/developmentToolsComponent/randomDateGenerator.tsx @@ -22,7 +22,7 @@ const RandomDateGenerator = () => { const startInputRef = useRef(null); const endInputRef = useRef(null); - const openPicker = (ref: React.RefObject) => { + const openPicker = (ref: React.RefObject) => { const el = ref.current; if (!el) return; // @ts-ignore - showPicker is supported in modern Chromium diff --git a/app/components/headerMenuDropdownComponents/productMenuComponent.tsx b/app/components/headerMenuDropdownComponents/productMenuComponent.tsx index 9ea84f4..83603ff 100644 --- a/app/components/headerMenuDropdownComponents/productMenuComponent.tsx +++ b/app/components/headerMenuDropdownComponents/productMenuComponent.tsx @@ -1,3 +1,4 @@ +'use client'; import Image from 'next/image'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; diff --git a/app/components/headerMenuDropdownComponents/resourceMenuComponent.tsx b/app/components/headerMenuDropdownComponents/resourceMenuComponent.tsx index 0e92645..8e42b89 100644 --- a/app/components/headerMenuDropdownComponents/resourceMenuComponent.tsx +++ b/app/components/headerMenuDropdownComponents/resourceMenuComponent.tsx @@ -1,3 +1,4 @@ +'use client'; import React from 'react'; import { usePathname } from 'next/navigation'; import Link from 'next/link'; diff --git a/app/components/layout/Header/headerComponent.tsx b/app/components/layout/Header/headerComponent.tsx index 544d22a..6ea72cb 100644 --- a/app/components/layout/Header/headerComponent.tsx +++ b/app/components/layout/Header/headerComponent.tsx @@ -1,5 +1,5 @@ 'use client'; -import { Button, Collapse, Drawer, Dropdown, Menu } from 'antd'; +import { Button, Collapse, Drawer, Dropdown } from 'antd'; import Image from 'next/image'; import Link from 'next/link'; import { usePathname, useSearchParams } from 'next/navigation'; @@ -386,12 +386,7 @@ const HeaderComponent = () => { (menu.label === 'Resources' && menu?.dropdown) ? ( ({ - key: index, - label:

{item?.label}

, - })), - }} + popupRender={() => menu?.dropdown?.[0]?.label ?? null} trigger={['hover']} >

{

- - {responsiveContentHeader?.map((item: any, index) => ( - - {item.header} -

- } - key={index} - > - {item.content &&

{item.content}

} -
- ))} -
+ ({ + key: index, + className: hederStyles.accordion, + label: ( +

+ {item.header} +

+ ), + children: item.content &&

{item.content}

, + }))} + /> {responsiveHeader?.map((data: any, index: any) => (

{ + if (!pathname || pathname === "/") return CANONICAL_BASE_PATH; + + if ( + pathname === CANONICAL_BASE_PATH || + pathname.startsWith(`${CANONICAL_BASE_PATH}/`) + ) { + return pathname; + } + + return `${CANONICAL_BASE_PATH}${pathname.startsWith("/") ? pathname : `/${pathname}`}`; +}; + const CanonicalLink = () => { const router = usePathname(); - let url = ""; - if (router === "/use-cases/[slug]") { - url = WEB_URL + router; - } else { - url = WEB_URL + router; - } - const canonicalURL = url; + const canonicalURL = WEB_URL + buildCanonicalPath(router); return ( <> diff --git a/app/layout.tsx b/app/layout.tsx index 00e570a..76b2287 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,38 +1,16 @@ -'use client'; import 'antd/dist/reset.css'; import './styles/global.scss'; import { Poppins } from 'next/font/google'; -import HeaderComponent from './components/layout/Header/headerComponent'; -import CanonicalLink from './components/theme/canonicalLink/canonicalLink'; -import { - LayoutContext, - LayoutContextModel, - LayoutContextProvider, -} from './contexts/layoutContexts'; -import { ThemeProvider } from './contexts/themeContext'; -import FooterComponent from './components/layout/footer/footerComponent'; -import { useMediaQuery } from 'react-responsive'; -import { Suspense, useContext } from 'react'; -import { CookiesProvider } from 'react-cookie'; +import { AntdRegistry } from '@ant-design/nextjs-registry'; import Script from 'next/script'; -import dynamic from 'next/dynamic'; - -const AnimatedCursor = dynamic(() => import('react-animated-cursor'), { - ssr: false, -}); +import ClientLayout from './ClientLayout'; const inter = Poppins({ subsets: ['latin'], weight: ['100', '200', '300', '400', '500', '600', '700', '800', '900'], }); -const MyApp = ({ children }: { children: JSX.Element }): JSX.Element => { - const { isClient }: LayoutContextModel = useContext(LayoutContext); - - const isDesktopOrLaptop = useMediaQuery({ - query: '(min-width: 1024px)', - }); - +const RootLayout = ({ children }: { children: React.ReactNode }) => { return ( @@ -41,7 +19,7 @@ const MyApp = ({ children }: { children: JSX.Element }): JSX.Element => { content="MdnRMoBETw7d7ltRJoXu8nAIg6ah5iUdVXpNp_fFGH8" /> - + + /> - + /> +