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

View File

@@ -1,29 +1,37 @@
import React, { useEffect, Suspense, lazy } from 'react'; import React, { useEffect, Suspense, lazy } from "react";
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import {
import { HelmetProvider } from 'react-helmet-async'; BrowserRouter as Router,
import Layout from './components/Layout'; Routes,
import ErrorBoundary from './components/ErrorBoundary'; Route,
import Loading from './components/Loading'; Navigate,
import { initGA } from './utils/analytics'; } 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 Home = lazy(() => import("./pages/Home"));
const UrlTool = lazy(() => import('./pages/UrlTool')); const UrlTool = lazy(() => import("./pages/UrlTool"));
const Base64Tool = lazy(() => import('./pages/Base64Tool')); const Base64Tool = lazy(() => import("./pages/Base64Tool"));
const BeautifierTool = lazy(() => import('./pages/BeautifierTool')); const BeautifierTool = lazy(() => import("./pages/BeautifierTool"));
const DiffTool = lazy(() => import('./pages/DiffTool')); const DiffTool = lazy(() => import("./pages/DiffTool"));
const TextLengthTool = lazy(() => import('./pages/TextLengthTool')); const TextLengthTool = lazy(() => import("./pages/TextLengthTool"));
const ObjectEditor = lazy(() => import('./pages/ObjectEditor')); const ObjectEditor = lazy(() => import("./pages/ObjectEditor"));
const TableEditor = lazy(() => import('./pages/TableEditor')); const TableEditor = lazy(() => import("./pages/TableEditor"));
const InvoiceEditor = lazy(() => import('./pages/InvoiceEditor')); const InvoiceEditor = lazy(() => import("./pages/InvoiceEditor"));
const MarkdownEditor = lazy(() => import('./pages/MarkdownEditor')); const MarkdownEditor = lazy(() => import("./pages/MarkdownEditor"));
const InvoicePreview = lazy(() => import('./pages/InvoicePreview')); const DiagramEditor = lazy(() => import("./pages/DiagramEditor"));
const InvoicePreviewMinimal = lazy(() => import('./pages/InvoicePreviewMinimal')); const InvoicePreview = lazy(() => import("./pages/InvoicePreview"));
const ReleaseNotes = lazy(() => import('./pages/ReleaseNotes')); const InvoicePreviewMinimal = lazy(
const TermsOfService = lazy(() => import('./pages/TermsOfService')); () => import("./pages/InvoicePreviewMinimal"),
const PrivacyPolicy = lazy(() => import('./pages/PrivacyPolicy')); );
const NotFound = lazy(() => import('./pages/NotFound')); 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() { function App() {
// Initialize Google Analytics on app startup // Initialize Google Analytics on app startup
@@ -48,9 +56,16 @@ function App() {
<Route path="/table-editor" element={<TableEditor />} /> <Route path="/table-editor" element={<TableEditor />} />
<Route path="/invoice-editor" element={<InvoiceEditor />} /> <Route path="/invoice-editor" element={<InvoiceEditor />} />
<Route path="/markdown-editor" element={<MarkdownEditor />} /> <Route path="/markdown-editor" element={<MarkdownEditor />} />
<Route path="/diagram-editor" element={<DiagramEditor />} />
<Route path="/invoice-preview" element={<InvoicePreview />} /> <Route path="/invoice-preview" element={<InvoicePreview />} />
<Route path="/invoice-preview-minimal" element={<InvoicePreviewMinimal />} /> <Route
<Route path="/whats-new" element={<Navigate to="/release-notes" replace />} /> path="/invoice-preview-minimal"
element={<InvoicePreviewMinimal />}
/>
<Route
path="/whats-new"
element={<Navigate to="/release-notes" replace />}
/>
<Route path="/release-notes" element={<ReleaseNotes />} /> <Route path="/release-notes" element={<ReleaseNotes />} />
<Route path="/privacy" element={<PrivacyPolicy />} /> <Route path="/privacy" element={<PrivacyPolicy />} />
<Route path="/terms" element={<TermsOfService />} /> <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 // Master tools configuration - single source of truth
export const TOOL_CATEGORIES = { export const TOOL_CATEGORIES = {
navigation: { navigation: {
name: 'Navigation', name: "Navigation",
color: 'from-slate-500 to-slate-600', color: "from-slate-500 to-slate-600",
hoverColor: 'slate-600', hoverColor: "slate-600",
textColor: 'text-slate-600', textColor: "text-slate-600",
hoverTextColor: 'hover:text-slate-700 dark:hover:text-slate-600' hoverTextColor: "hover:text-slate-700 dark:hover:text-slate-600",
}, },
editor: { editor: {
name: 'Editor', name: "Editor",
color: 'from-blue-500 to-cyan-500', color: "from-blue-500 to-cyan-500",
hoverColor: 'blue-600', hoverColor: "blue-600",
textColor: 'text-blue-600', textColor: "text-blue-600",
hoverTextColor: 'hover:text-blue-700 dark:hover:text-blue-400' hoverTextColor: "hover:text-blue-700 dark:hover:text-blue-400",
}, },
encoder: { encoder: {
name: 'Encoder', name: "Encoder",
color: 'from-purple-500 to-pink-500', color: "from-purple-500 to-pink-500",
hoverColor: 'purple-600', hoverColor: "purple-600",
textColor: 'text-purple-600', textColor: "text-purple-600",
hoverTextColor: 'hover:text-purple-700 dark:hover:text-purple-400' hoverTextColor: "hover:text-purple-700 dark:hover:text-purple-400",
}, },
formatter: { formatter: {
name: 'Formatter', name: "Formatter",
color: 'from-green-500 to-emerald-500', color: "from-green-500 to-emerald-500",
hoverColor: 'green-600', hoverColor: "green-600",
textColor: 'text-green-600', textColor: "text-green-600",
hoverTextColor: 'hover:text-green-700 dark:hover:text-green-400' hoverTextColor: "hover:text-green-700 dark:hover:text-green-400",
}, },
analyzer: { analyzer: {
name: 'Analyzer', name: "Analyzer",
color: 'from-orange-500 to-red-500', color: "from-orange-500 to-red-500",
hoverColor: 'orange-600', hoverColor: "orange-600",
textColor: 'text-orange-600', textColor: "text-orange-600",
hoverTextColor: 'hover:text-orange-700 dark:hover:text-orange-400' hoverTextColor: "hover:text-orange-700 dark:hover:text-orange-400",
}, },
non_tools: { non_tools: {
name: 'Site Navigation', name: "Site Navigation",
color: 'from-indigo-500 to-purple-500', color: "from-indigo-500 to-purple-500",
hoverColor: 'indigo-600', hoverColor: "indigo-600",
textColor: 'text-indigo-600', textColor: "text-indigo-600",
hoverTextColor: 'hover:text-indigo-700 dark:hover:text-indigo-400' hoverTextColor: "hover:text-indigo-700 dark:hover:text-indigo-400",
} },
}; };
export const TOOLS = [ export const TOOLS = [
{ {
path: '/object-editor', path: "/object-editor",
name: 'Object Editor', name: "Object Editor",
icon: Edit3, icon: Edit3,
description: 'Visual editor for JSON and PHP serialized objects with mindmap visualization', description:
tags: ['Visual', 'JSON', 'PHP', 'Objects', 'Editor'], "Visual editor for JSON and PHP serialized objects with mindmap visualization",
category: 'editor' tags: ["Visual", "JSON", "PHP", "Objects", "Editor"],
category: "editor",
}, },
{ {
path: '/table-editor', path: "/table-editor",
name: 'Table Editor', name: "Table Editor",
icon: Table, icon: Table,
description: 'Import, edit, and export tabular data from URLs, files, or paste CSV/JSON', description:
tags: ['Table', 'CSV', 'JSON', 'Data', 'Editor'], "Import, edit, and export tabular data from URLs, files, or paste CSV/JSON",
category: 'editor' tags: ["Table", "CSV", "JSON", "Data", "Editor"],
category: "editor",
}, },
{ {
path: '/markdown-editor', path: "/markdown-editor",
name: 'Markdown Editor', name: "Markdown Editor",
icon: FileText, icon: FileText,
description: 'Write and preview markdown with live rendering, syntax highlighting, and export options', description:
tags: ['Markdown', 'Editor', 'Preview', 'Export', 'GFM'], "Write and preview markdown with live rendering, syntax highlighting, and export options",
category: 'editor' tags: ["Markdown", "Editor", "Preview", "Export", "GFM"],
category: "editor",
}, },
{ {
path: '/invoice-editor', path: "/diagram-editor",
name: 'Invoice 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, icon: FileText,
description: 'Create, edit, and export professional invoices with PDF generation', description:
tags: ['Invoice', 'PDF', 'Business', 'Billing', 'Export'], "Create, edit, and export professional invoices with PDF generation",
category: 'editor' tags: ["Invoice", "PDF", "Business", "Billing", "Export"],
category: "editor",
}, },
{ {
path: '/url', path: "/url",
name: 'URL Encoder/Decoder', name: "URL Encoder/Decoder",
icon: LinkIcon, icon: LinkIcon,
description: 'Encode and decode URLs and query parameters', description: "Encode and decode URLs and query parameters",
tags: ['URL', 'Encode', 'Decode'], tags: ["URL", "Encode", "Decode"],
category: 'encoder' category: "encoder",
}, },
{ {
path: '/base64', path: "/base64",
name: 'Base64 Encoder/Decoder', name: "Base64 Encoder/Decoder",
icon: Hash, icon: Hash,
description: 'Convert text to Base64 and back with support for files', description: "Convert text to Base64 and back with support for files",
tags: ['Base64', 'Encode', 'Binary'], tags: ["Base64", "Encode", "Binary"],
category: 'encoder' category: "encoder",
}, },
{ {
path: '/beautifier', path: "/beautifier",
name: 'Code Beautifier/Minifier', name: "Code Beautifier/Minifier",
icon: Wand2, icon: Wand2,
description: 'Format and minify JSON, XML, SQL, CSS, and HTML code', description: "Format and minify JSON, XML, SQL, CSS, and HTML code",
tags: ['Format', 'Minify', 'Beautify'], tags: ["Format", "Minify", "Beautify"],
category: 'formatter' category: "formatter",
}, },
{ {
path: '/diff', path: "/diff",
name: 'Text Diff Checker', name: "Text Diff Checker",
icon: GitCompare, icon: GitCompare,
description: 'Compare two texts and highlight differences line by line', description: "Compare two texts and highlight differences line by line",
tags: ['Diff', 'Compare', 'Text'], tags: ["Diff", "Compare", "Text"],
category: 'analyzer' category: "analyzer",
}, },
{ {
path: '/text-length', path: "/text-length",
name: 'Text Length Checker', name: "Text Length Checker",
icon: Type, icon: Type,
description: 'Analyze text length, word count, and other text statistics', description: "Analyze text length, word count, and other text statistics",
tags: ['Text', 'Length', 'Statistics'], tags: ["Text", "Length", "Statistics"],
category: 'analyzer' category: "analyzer",
} },
]; ];
// Non-tool navigation items (homepage, what's new, etc.) // Non-tool navigation items (homepage, what's new, etc.)
export const NON_TOOLS = [ export const NON_TOOLS = [
{ {
path: '/', path: "/",
name: 'Home', name: "Home",
icon: Home, icon: Home,
description: 'Back to homepage', description: "Back to homepage",
category: 'non_tools' category: "non_tools",
} },
]; ];
// Navigation tools (for sidebar) - combines non-tools and tools // Navigation tools (for sidebar) - combines non-tools and tools
export const NAVIGATION_TOOLS = [ export const NAVIGATION_TOOLS = [...NON_TOOLS, ...TOOLS];
...NON_TOOLS,
...TOOLS
];
// Site configuration // Site configuration
export const SITE_CONFIG = { export const SITE_CONFIG = {
domain: 'https://dewe.dev', domain: "https://dewe.dev",
title: 'Dewe.Dev', title: "Dewe.Dev",
subtitle: 'Professional Developer Utilities', subtitle: "Professional Developer Utilities",
slogan: 'Code faster, debug smarter, ship better', slogan: "Code faster, debug smarter, ship better",
description: 'Professional-grade utilities for modern developers', description: "Professional-grade utilities for modern developers",
year: new Date().getFullYear(), year: new Date().getFullYear(),
totalTools: TOOLS.length totalTools: TOOLS.length,
}; };
// Helper functions // 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 = () => { export const getCategoryStats = () => {
const stats = {}; const stats = {};
Object.keys(TOOL_CATEGORIES).forEach(key => { Object.keys(TOOL_CATEGORIES).forEach((key) => {
if (key !== 'navigation') { if (key !== "navigation") {
stats[key] = getToolsByCategory(key).length; stats[key] = getToolsByCategory(key).length;
} }
}); });