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 (
+ Swiftly document and share bugs like never before +
++ Free Forever. No Credit Card Required. +
++ 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 +
+
+ {hero_section?.description
+ ?.split('BetterBugs.io')
+ .map((part: any, index: any, arr: any) => (
+
+ {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 ( ++ {exampleItem.example_input} +
+ {isStringOutput && ( ++ {exampleItem.example_output} +
+ )} + > + )} + {isInputOrOutput && ( + <> ++ {exampleItem.example_input} +
+ {isArrayOutput && ( ++ {outputItem?.value} +
+ ) + )} +
+ {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 (
+
+ {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_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 && ( +
+ {p?.steps_points_description
+ ?.split(/((['"]).*?\2)/)
+ .map(
+ (part: string, i: number) =>
+ typeof part === 'string' &&
+ /^(['"]).*\1$/.test(
+ part
+ ) ? (
+
+ {part}
+
+ ) : (
+
+ {development_tool_example?.example_description} +
+ )} + + {development_tool_example?.example_input && ( ++ {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?.intro} +
+ )} + {development_tool_example?.example_outputs?.outputs?.map( + (output: any, index: number) => ( ++ {output?.mode} +
+ )} + {output?.title && ( ++ {output?.title} +
+ )} + {output?.content && ( +
+
+ {output?.content}
+
+
+ )}
+ {output?.note && (
+ + {output?.note} +
+ )} ++ { + development_tool_example?.javascript_example + ?.description + } +
+ )} + + {development_tool_example?.javascript_example?.methods + ?.length > 0 && ( ++ {example?.title} +
+ )} + {example?.code && ( +
+
+ {example?.code}
+
+
+ )}
+ + { + development_tool_example?.javascript_example + ?.note + } +
+ )} ++ {splitDescriptions.map( + (text: any, subIndex: any) => { + const isQuoted = + typeof text === 'string' && + /^(['"]).*\1$/.test(text); + + return ( + + {text} + + ); + } + )} +
+ ); + } + )} ++ {development_tools_how_use?.how_use_description} +
+ > + )} + {development_tools_how_use?.point?.length > 0 && ( ++ {how?.heading} +
+ ) : ( ++ {d?.desc} +
+ ) + )} ++ Swiftly document and share bugs like never before +
++ Free Forever. No Credit Card Required. +
++ 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 +
+
+ Two-way sync with
+
popular tools
+
+ {tool?.name} +
+- Swiftly document and share bugs like never before -
-- Free Forever. No Credit Card Required. -
-- 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 -
-
- {hero_section?.description
- ?.split('BetterBugs.io')
- .map((part: any, index: any, arr: any) => (
-
- {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 ( -- {exampleItem.example_input} -
- {isStringOutput && ( -- {exampleItem.example_output} -
- )} - > - )} - {isInputOrOutput && ( - <> -- {exampleItem.example_input} -
- {isArrayOutput && ( -- {outputItem?.value} -
- ) - )} -
- {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 (
-
- {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_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 && ( -
- {p?.steps_points_description
- ?.split(/((['"]).*?\2)/)
- .map((part: string, i: number) =>
- typeof part === "string" &&
- /^(['"]).*\1$/.test(part) ? (
-
- {part}
-
- ) : (
-
- {development_tool_example?.example_description} -
- )} - - {development_tool_example?.example_input && ( -- {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?.intro} -
- )} - {development_tool_example?.example_outputs?.outputs?.map( - (output: any, index: number) => ( -- {output?.mode} -
- )} - {output?.title && ( -- {output?.title} -
- )} - {output?.content && ( -
-
- {output?.content}
-
-
- )}
- {output?.note && (
- - {output?.note} -
- )} -- { - development_tool_example?.javascript_example - ?.description - } -
- )} - - {development_tool_example?.javascript_example?.methods - ?.length > 0 && ( -- {example?.title} -
- )} - {example?.code && ( -
-
- {example?.code}
-
-
- )}
- - { - development_tool_example?.javascript_example - ?.note - } -
- )} -- {splitDescriptions.map( - (text: any, subIndex: any) => { - const isQuoted = - typeof text === "string" && - /^(['"]).*\1$/.test(text); - - return ( - - {text} - - ); - } - )} -
- ); - } - )} -- {development_tools_how_use?.how_use_description} -
- > - )} - {development_tools_how_use?.point?.length > 0 && ( -- {how?.heading} -
- ) : ( -- {d?.desc} -
- ) - )} -- Swiftly document and share bugs like never before -
-- Free Forever. No Credit Card Required. -
-- 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 -
-
- Two-way sync with
-
popular tools
-
- {tool?.name} -
-{faq?.des}
- - ))} -{item?.label}
, - })), - }} + popupRender={() => menu?.dropdown?.[0]?.label ?? null} trigger={['hover']} >{
{item.content}
} -+ {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" /> - + {process.env.NEXT_ENV === 'PRODUCTION' && ( <> + /> - + /> + -