fix(diagram): resolve DOMURL undefined error causing build failure

This commit is contained in:
Dwindi Ramadhana
2026-06-14 15:55:08 +07:00
parent deb2bf0b8a
commit 518b0127d2
4 changed files with 1010 additions and 411 deletions

1102
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,7 @@
"lucide-react": "^0.540.0",
"marked": "^16.4.1",
"marked-emoji": "^2.0.1",
"mermaid": "^11.15.0",
"papaparse": "^5.5.3",
"react": "18.3.1",
"react-diff-view": "^3.3.2",
@@ -54,6 +55,7 @@
"react-helmet-async": "^2.0.5",
"react-router-dom": "6.26.2",
"react-snap": "^1.23.0",
"react-zoom-pan-pinch": "^4.0.3",
"reactflow": "^11.11.4",
"serialize-javascript": "^6.0.0",
"serve": "^14.2.4",

View File

@@ -1,29 +1,37 @@
import React, { useEffect, Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';
import Layout from './components/Layout';
import ErrorBoundary from './components/ErrorBoundary';
import Loading from './components/Loading';
import { initGA } from './utils/analytics';
import React, { useEffect, Suspense, lazy } from "react";
import {
BrowserRouter as Router,
Routes,
Route,
Navigate,
} from "react-router-dom";
import { HelmetProvider } from "react-helmet-async";
import Layout from "./components/Layout";
import ErrorBoundary from "./components/ErrorBoundary";
import Loading from "./components/Loading";
import { initGA } from "./utils/analytics";
import './index.css';
import "./index.css";
const Home = lazy(() => import('./pages/Home'));
const UrlTool = lazy(() => import('./pages/UrlTool'));
const Base64Tool = lazy(() => import('./pages/Base64Tool'));
const BeautifierTool = lazy(() => import('./pages/BeautifierTool'));
const DiffTool = lazy(() => import('./pages/DiffTool'));
const TextLengthTool = lazy(() => import('./pages/TextLengthTool'));
const ObjectEditor = lazy(() => import('./pages/ObjectEditor'));
const TableEditor = lazy(() => import('./pages/TableEditor'));
const InvoiceEditor = lazy(() => import('./pages/InvoiceEditor'));
const MarkdownEditor = lazy(() => import('./pages/MarkdownEditor'));
const InvoicePreview = lazy(() => import('./pages/InvoicePreview'));
const InvoicePreviewMinimal = lazy(() => import('./pages/InvoicePreviewMinimal'));
const ReleaseNotes = lazy(() => import('./pages/ReleaseNotes'));
const TermsOfService = lazy(() => import('./pages/TermsOfService'));
const PrivacyPolicy = lazy(() => import('./pages/PrivacyPolicy'));
const NotFound = lazy(() => import('./pages/NotFound'));
const Home = lazy(() => import("./pages/Home"));
const UrlTool = lazy(() => import("./pages/UrlTool"));
const Base64Tool = lazy(() => import("./pages/Base64Tool"));
const BeautifierTool = lazy(() => import("./pages/BeautifierTool"));
const DiffTool = lazy(() => import("./pages/DiffTool"));
const TextLengthTool = lazy(() => import("./pages/TextLengthTool"));
const ObjectEditor = lazy(() => import("./pages/ObjectEditor"));
const TableEditor = lazy(() => import("./pages/TableEditor"));
const InvoiceEditor = lazy(() => import("./pages/InvoiceEditor"));
const MarkdownEditor = lazy(() => import("./pages/MarkdownEditor"));
const DiagramEditor = lazy(() => import("./pages/DiagramEditor"));
const InvoicePreview = lazy(() => import("./pages/InvoicePreview"));
const InvoicePreviewMinimal = lazy(
() => import("./pages/InvoicePreviewMinimal"),
);
const ReleaseNotes = lazy(() => import("./pages/ReleaseNotes"));
const TermsOfService = lazy(() => import("./pages/TermsOfService"));
const PrivacyPolicy = lazy(() => import("./pages/PrivacyPolicy"));
const NotFound = lazy(() => import("./pages/NotFound"));
function App() {
// Initialize Google Analytics on app startup
@@ -48,9 +56,16 @@ function App() {
<Route path="/table-editor" element={<TableEditor />} />
<Route path="/invoice-editor" element={<InvoiceEditor />} />
<Route path="/markdown-editor" element={<MarkdownEditor />} />
<Route path="/diagram-editor" element={<DiagramEditor />} />
<Route path="/invoice-preview" element={<InvoicePreview />} />
<Route path="/invoice-preview-minimal" element={<InvoicePreviewMinimal />} />
<Route path="/whats-new" element={<Navigate to="/release-notes" replace />} />
<Route
path="/invoice-preview-minimal"
element={<InvoicePreviewMinimal />}
/>
<Route
path="/whats-new"
element={<Navigate to="/release-notes" replace />}
/>
<Route path="/release-notes" element={<ReleaseNotes />} />
<Route path="/privacy" element={<PrivacyPolicy />} />
<Route path="/terms" element={<TermsOfService />} />

View File

@@ -1,163 +1,185 @@
import { Edit3, Table, LinkIcon, Hash, Wand2, GitCompare, Type, Home, FileText } from 'lucide-react';
import {
Edit3,
Table,
LinkIcon,
Hash,
Wand2,
GitCompare,
Type,
Home,
FileText,
} from "lucide-react";
// Master tools configuration - single source of truth
export const TOOL_CATEGORIES = {
navigation: {
name: 'Navigation',
color: 'from-slate-500 to-slate-600',
hoverColor: 'slate-600',
textColor: 'text-slate-600',
hoverTextColor: 'hover:text-slate-700 dark:hover:text-slate-600'
name: "Navigation",
color: "from-slate-500 to-slate-600",
hoverColor: "slate-600",
textColor: "text-slate-600",
hoverTextColor: "hover:text-slate-700 dark:hover:text-slate-600",
},
editor: {
name: 'Editor',
color: 'from-blue-500 to-cyan-500',
hoverColor: 'blue-600',
textColor: 'text-blue-600',
hoverTextColor: 'hover:text-blue-700 dark:hover:text-blue-400'
name: "Editor",
color: "from-blue-500 to-cyan-500",
hoverColor: "blue-600",
textColor: "text-blue-600",
hoverTextColor: "hover:text-blue-700 dark:hover:text-blue-400",
},
encoder: {
name: 'Encoder',
color: 'from-purple-500 to-pink-500',
hoverColor: 'purple-600',
textColor: 'text-purple-600',
hoverTextColor: 'hover:text-purple-700 dark:hover:text-purple-400'
name: "Encoder",
color: "from-purple-500 to-pink-500",
hoverColor: "purple-600",
textColor: "text-purple-600",
hoverTextColor: "hover:text-purple-700 dark:hover:text-purple-400",
},
formatter: {
name: 'Formatter',
color: 'from-green-500 to-emerald-500',
hoverColor: 'green-600',
textColor: 'text-green-600',
hoverTextColor: 'hover:text-green-700 dark:hover:text-green-400'
name: "Formatter",
color: "from-green-500 to-emerald-500",
hoverColor: "green-600",
textColor: "text-green-600",
hoverTextColor: "hover:text-green-700 dark:hover:text-green-400",
},
analyzer: {
name: 'Analyzer',
color: 'from-orange-500 to-red-500',
hoverColor: 'orange-600',
textColor: 'text-orange-600',
hoverTextColor: 'hover:text-orange-700 dark:hover:text-orange-400'
name: "Analyzer",
color: "from-orange-500 to-red-500",
hoverColor: "orange-600",
textColor: "text-orange-600",
hoverTextColor: "hover:text-orange-700 dark:hover:text-orange-400",
},
non_tools: {
name: 'Site Navigation',
color: 'from-indigo-500 to-purple-500',
hoverColor: 'indigo-600',
textColor: 'text-indigo-600',
hoverTextColor: 'hover:text-indigo-700 dark:hover:text-indigo-400'
}
name: "Site Navigation",
color: "from-indigo-500 to-purple-500",
hoverColor: "indigo-600",
textColor: "text-indigo-600",
hoverTextColor: "hover:text-indigo-700 dark:hover:text-indigo-400",
},
};
export const TOOLS = [
{
path: '/object-editor',
name: 'Object Editor',
path: "/object-editor",
name: "Object Editor",
icon: Edit3,
description: 'Visual editor for JSON and PHP serialized objects with mindmap visualization',
tags: ['Visual', 'JSON', 'PHP', 'Objects', 'Editor'],
category: 'editor'
description:
"Visual editor for JSON and PHP serialized objects with mindmap visualization",
tags: ["Visual", "JSON", "PHP", "Objects", "Editor"],
category: "editor",
},
{
path: '/table-editor',
name: 'Table Editor',
path: "/table-editor",
name: "Table Editor",
icon: Table,
description: 'Import, edit, and export tabular data from URLs, files, or paste CSV/JSON',
tags: ['Table', 'CSV', 'JSON', 'Data', 'Editor'],
category: 'editor'
description:
"Import, edit, and export tabular data from URLs, files, or paste CSV/JSON",
tags: ["Table", "CSV", "JSON", "Data", "Editor"],
category: "editor",
},
{
path: '/markdown-editor',
name: 'Markdown Editor',
path: "/markdown-editor",
name: "Markdown Editor",
icon: FileText,
description: 'Write and preview markdown with live rendering, syntax highlighting, and export options',
tags: ['Markdown', 'Editor', 'Preview', 'Export', 'GFM'],
category: 'editor'
description:
"Write and preview markdown with live rendering, syntax highlighting, and export options",
tags: ["Markdown", "Editor", "Preview", "Export", "GFM"],
category: "editor",
},
{
path: '/invoice-editor',
name: 'Invoice Editor',
path: "/diagram-editor",
name: "Diagram Editor",
icon: Edit3,
description:
"Create diagrams as code using Mermaid.js with live preview and multi-format export",
tags: ["Diagram", "Mermaid", "Architecture", "Flowchart", "Visual"],
category: "editor",
},
{
path: "/invoice-editor",
name: "Invoice Editor",
icon: FileText,
description: 'Create, edit, and export professional invoices with PDF generation',
tags: ['Invoice', 'PDF', 'Business', 'Billing', 'Export'],
category: 'editor'
description:
"Create, edit, and export professional invoices with PDF generation",
tags: ["Invoice", "PDF", "Business", "Billing", "Export"],
category: "editor",
},
{
path: '/url',
name: 'URL Encoder/Decoder',
path: "/url",
name: "URL Encoder/Decoder",
icon: LinkIcon,
description: 'Encode and decode URLs and query parameters',
tags: ['URL', 'Encode', 'Decode'],
category: 'encoder'
description: "Encode and decode URLs and query parameters",
tags: ["URL", "Encode", "Decode"],
category: "encoder",
},
{
path: '/base64',
name: 'Base64 Encoder/Decoder',
path: "/base64",
name: "Base64 Encoder/Decoder",
icon: Hash,
description: 'Convert text to Base64 and back with support for files',
tags: ['Base64', 'Encode', 'Binary'],
category: 'encoder'
description: "Convert text to Base64 and back with support for files",
tags: ["Base64", "Encode", "Binary"],
category: "encoder",
},
{
path: '/beautifier',
name: 'Code Beautifier/Minifier',
path: "/beautifier",
name: "Code Beautifier/Minifier",
icon: Wand2,
description: 'Format and minify JSON, XML, SQL, CSS, and HTML code',
tags: ['Format', 'Minify', 'Beautify'],
category: 'formatter'
description: "Format and minify JSON, XML, SQL, CSS, and HTML code",
tags: ["Format", "Minify", "Beautify"],
category: "formatter",
},
{
path: '/diff',
name: 'Text Diff Checker',
path: "/diff",
name: "Text Diff Checker",
icon: GitCompare,
description: 'Compare two texts and highlight differences line by line',
tags: ['Diff', 'Compare', 'Text'],
category: 'analyzer'
description: "Compare two texts and highlight differences line by line",
tags: ["Diff", "Compare", "Text"],
category: "analyzer",
},
{
path: '/text-length',
name: 'Text Length Checker',
path: "/text-length",
name: "Text Length Checker",
icon: Type,
description: 'Analyze text length, word count, and other text statistics',
tags: ['Text', 'Length', 'Statistics'],
category: 'analyzer'
}
description: "Analyze text length, word count, and other text statistics",
tags: ["Text", "Length", "Statistics"],
category: "analyzer",
},
];
// Non-tool navigation items (homepage, what's new, etc.)
export const NON_TOOLS = [
{
path: '/',
name: 'Home',
path: "/",
name: "Home",
icon: Home,
description: 'Back to homepage',
category: 'non_tools'
}
description: "Back to homepage",
category: "non_tools",
},
];
// Navigation tools (for sidebar) - combines non-tools and tools
export const NAVIGATION_TOOLS = [
...NON_TOOLS,
...TOOLS
];
export const NAVIGATION_TOOLS = [...NON_TOOLS, ...TOOLS];
// Site configuration
export const SITE_CONFIG = {
domain: 'https://dewe.dev',
title: 'Dewe.Dev',
subtitle: 'Professional Developer Utilities',
slogan: 'Code faster, debug smarter, ship better',
description: 'Professional-grade utilities for modern developers',
domain: "https://dewe.dev",
title: "Dewe.Dev",
subtitle: "Professional Developer Utilities",
slogan: "Code faster, debug smarter, ship better",
description: "Professional-grade utilities for modern developers",
year: new Date().getFullYear(),
totalTools: TOOLS.length
totalTools: TOOLS.length,
};
// Helper functions
export const getCategoryConfig = (categoryKey) => TOOL_CATEGORIES[categoryKey] || TOOL_CATEGORIES.navigation;
export const getCategoryConfig = (categoryKey) =>
TOOL_CATEGORIES[categoryKey] || TOOL_CATEGORIES.navigation;
export const getToolsByCategory = (categoryKey) => TOOLS.filter(tool => tool.category === categoryKey);
export const getToolsByCategory = (categoryKey) =>
TOOLS.filter((tool) => tool.category === categoryKey);
export const getCategoryStats = () => {
const stats = {};
Object.keys(TOOL_CATEGORIES).forEach(key => {
if (key !== 'navigation') {
Object.keys(TOOL_CATEGORIES).forEach((key) => {
if (key !== "navigation") {
stats[key] = getToolsByCategory(key).length;
}
});