From 7792190ea1500b1a21a5680ab43fac14e5c96a4e Mon Sep 17 00:00:00 2001 From: dwindown Date: Wed, 24 Sep 2025 19:02:12 +0700 Subject: [PATCH] feat: Enhanced What's New feature with NON_TOOLS category and global footer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✨ What's New Feature & Navigation Improvements: - Added attractive 'What's New' button to homepage with gradient design and sparkle effects - Created NON_TOOLS category for better navigation organization (Home, What's New) - Separated navigation items in sidebar and mobile menu with clear visual hierarchy - Implemented unified global footer across all pages for consistency 🎨 Design Enhancements: - Stunning gradient button with indigo→purple→pink colors and hover animations - Perfect placement between stats and tools grid for maximum visibility - Consistent indigo-purple theming for non-tools category - Professional sparkle effects and scale transforms on hover 🔧 Technical Improvements: - Removed duplicate footer from Terms of Service page - Unified footer implementation reduces code duplication - Enhanced mobile dropdown with proper NON_TOOLS separation - Updated sidebar with category-based styling and separators 📁 Files Modified: - /src/config/tools.js - Added NON_TOOLS category and What's New entry - /src/components/ToolSidebar.js - Separated NON_TOOLS with visual hierarchy - /src/components/Layout.js - Updated mobile menu and implemented global footer - /src/pages/Home.js - Added attractive What's New button with animations - /src/pages/TermsOfService.js - Removed duplicate footer - /src/pages/ReleaseNotes.js - Updated with latest implementation details --- src/App.js | 2 + src/components/Layout.js | 203 ++++++++--------- src/components/ToolSidebar.js | 95 +++++++- src/config/tools.js | 27 ++- src/pages/Home.js | 36 ++- src/pages/ReleaseNotes.js | 402 ++++++++++++++++++++++++++++++++++ src/pages/TableEditor.js | 112 ++++++---- src/pages/TermsOfService.js | 7 - 8 files changed, 724 insertions(+), 160 deletions(-) create mode 100644 src/pages/ReleaseNotes.js diff --git a/src/App.js b/src/App.js index efca6312..b9cb1133 100644 --- a/src/App.js +++ b/src/App.js @@ -13,6 +13,7 @@ import DiffTool from './pages/DiffTool'; import TextLengthTool from './pages/TextLengthTool'; import ObjectEditor from './pages/ObjectEditor'; import TableEditor from './pages/TableEditor'; +import ReleaseNotes from './pages/ReleaseNotes'; import TermsOfService from './pages/TermsOfService'; import PrivacyPolicy from './pages/PrivacyPolicy'; import { initGA } from './utils/analytics'; @@ -41,6 +42,7 @@ function App() { } /> } /> } /> + } /> } /> } /> diff --git a/src/components/Layout.js b/src/components/Layout.js index 13101421..7f1b0823 100644 --- a/src/components/Layout.js +++ b/src/components/Layout.js @@ -5,7 +5,7 @@ import ThemeToggle from './ThemeToggle'; import ToolSidebar from './ToolSidebar'; import SEOHead from './SEOHead'; import ConsentBanner from './ConsentBanner'; -import { TOOLS, SITE_CONFIG, getCategoryConfig } from '../config/tools'; +import { NON_TOOLS, TOOLS, SITE_CONFIG, getCategoryConfig } from '../config/tools'; import { useAnalytics } from '../hooks/useAnalytics'; const Layout = ({ children }) => { @@ -161,18 +161,29 @@ const Layout = ({ children }) => {
- setIsMobileMenuOpen(false)} - className={`flex items-center space-x-3 px-4 py-3 rounded-xl text-sm font-medium transition-all duration-300 ${ - isActive('/') - ? 'bg-gradient-to-r from-blue-500 to-purple-500 text-white shadow-lg' - : 'text-slate-600 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white hover:bg-white/50 dark:hover:bg-slate-700/50' - }`} - > - - Home - + {/* Non-Tools Section */} + {NON_TOOLS.map((tool) => { + const IconComponent = tool.icon; + const categoryConfig = getCategoryConfig(tool.category); + + return ( + setIsMobileMenuOpen(false)} + className={`flex items-center space-x-3 px-4 py-3 rounded-xl text-sm font-medium transition-all duration-300 ${ + isActive(tool.path) + ? 'bg-gradient-to-r from-indigo-500 to-purple-500 text-white shadow-lg' + : 'text-slate-600 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white hover:bg-white/50 dark:hover:bg-slate-700/50' + }`} + > +
+ +
+ {tool.name} + + ); + })}
@@ -216,117 +227,93 @@ const Layout = ({ children }) => { {/* Tool Sidebar - only show on tool pages */} {isToolPage && (
-
)} {/* Main Content Area */} -
+
{isToolPage ? ( -
-
+
+ +
{children}
- {/* Footer for tool pages - inside scrollable content */} -
-
-
-
-
- - © {SITE_CONFIG.year} {SITE_CONFIG.title} - -
-
-

- Built with ❤️ for developers worldwide -

-
- - Privacy Policy - - - - Terms of Service - -
-
-
-
) : (
{children} - {/* Footer for homepage */} -
-
-
-
-
-
-
- -
-
- - {SITE_CONFIG.title} - -
-
-
- - © {SITE_CONFIG.year} {SITE_CONFIG.title} - -
-
-

- {SITE_CONFIG.description} -

-
-
-
-
- 100% Client-Side -
-
-
- Privacy First -
-
-
- Open Source -
-
-
- - Privacy Policy - - - - Terms of Service - -
-
-
-
-
)}
+ {/* Global Footer */} +
+
+
+
+
+
+
+ +
+
+ + {SITE_CONFIG.title} + +
+
+
+ + © {SITE_CONFIG.year} {SITE_CONFIG.title} + +
+
+

+ Built with ❤️ for developers worldwide +

+
+
+
+
+ 100% Client-Side +
+
+
+ Privacy First +
+
+
+ Open Source +
+
+
+ + Release Notes + + + + Privacy Policy + + + + Terms of Service + +
+
+
+
+
+ {/* GDPR Consent Banner */}
diff --git a/src/components/ToolSidebar.js b/src/components/ToolSidebar.js index b949aaca..0d72eb94 100644 --- a/src/components/ToolSidebar.js +++ b/src/components/ToolSidebar.js @@ -1,14 +1,20 @@ import React, { useState } from 'react'; import { Link, useLocation } from 'react-router-dom'; import { Search, ChevronLeft, ChevronRight, Sparkles } from 'lucide-react'; -import { NAVIGATION_TOOLS, SITE_CONFIG } from '../config/tools'; +import { NON_TOOLS, TOOLS, SITE_CONFIG } from '../config/tools'; const ToolSidebar = () => { const location = useLocation(); const [isCollapsed, setIsCollapsed] = useState(true); const [searchTerm, setSearchTerm] = useState(''); - const filteredTools = NAVIGATION_TOOLS.filter(tool => + // Filter non-tools and tools separately + const filteredNonTools = NON_TOOLS.filter(tool => + tool.name.toLowerCase().includes(searchTerm.toLowerCase()) || + tool.description.toLowerCase().includes(searchTerm.toLowerCase()) + ); + + const filteredTools = TOOLS.filter(tool => tool.name.toLowerCase().includes(searchTerm.toLowerCase()) || tool.description.toLowerCase().includes(searchTerm.toLowerCase()) ); @@ -64,6 +70,76 @@ const ToolSidebar = () => { {/* Tools List */}
{/* Stats */} -
+
{SITE_CONFIG.totalTools} Tools Available @@ -85,6 +86,37 @@ const Home = () => { Zero Data Collection
+ + {/* What's New Button */} +
+ + {/* Animated background effect */} +
+ + {/* Sparkle effect */} +
+
+
+
+
+ +
+
+ +
+
+
What's New
+
+ Latest updates & features +
+
+ +
+ +
{/* Tools Grid */} diff --git a/src/pages/ReleaseNotes.js b/src/pages/ReleaseNotes.js new file mode 100644 index 00000000..16a6253e --- /dev/null +++ b/src/pages/ReleaseNotes.js @@ -0,0 +1,402 @@ +import React, { useState, useEffect } from 'react'; +import { Calendar, Sparkles, Bug, Zap, Shield, ChevronDown, ChevronUp } from 'lucide-react'; +import ToolLayout from '../components/ToolLayout'; + +const ReleaseNotes = () => { + const [releases, setReleases] = useState([]); + const [loading, setLoading] = useState(true); + const [expandedReleases, setExpandedReleases] = useState(new Set()); + + // Parse commit messages into user-friendly release notes + const parseCommitMessage = (message) => { + // Skip non-user-informative commits + const skipPatterns = [ + /^fix eslint/i, + /^remove.*eslint/i, + /^update.*package/i, + /^add debug/i, + /^fix.*dependency/i, + /deployment/i, + /^fix.*mismatch/i + ]; + + if (skipPatterns.some(pattern => pattern.test(message))) { + return null; + } + + // Transform commit messages to user-friendly descriptions + const transformations = [ + { + pattern: /feat.*enhanced.*what.*new.*feature.*non_tools.*category.*global.*footer/i, + type: 'feature', + title: 'What\'s New Feature & Navigation Improvements', + description: 'Added attractive "What\'s New" button to homepage, created NON_TOOLS category for better navigation organization, separated navigation items in sidebar and mobile menu, and implemented unified global footer across all pages' + }, + { + pattern: /improve.*objecteditor.*postmantable.*ui\/ux/i, + type: 'enhancement', + title: 'Enhanced Object Editor & Table View', + description: 'Improved user interface and experience with better JSON parsing, HTML rendering, and copy functionality' + }, + { + pattern: /feat.*analytics.*mobile.*ui/i, + type: 'feature', + title: 'Mobile UI Improvements', + description: 'Optimized interface for mobile devices with better analytics integration' + }, + { + pattern: /feat.*seo.*gdpr/i, + type: 'feature', + title: 'SEO & Privacy Compliance', + description: 'Comprehensive SEO optimization and GDPR compliance features for better discoverability and privacy protection' + }, + { + pattern: /improve.*objecteditor.*tableeditor/i, + type: 'enhancement', + title: 'Enhanced Data Editors', + description: 'Major improvements to Object Editor and new Table Editor with advanced data manipulation features' + }, + { + pattern: /enhanced.*object.*editor.*fetch.*mobile/i, + type: 'feature', + title: 'Object Editor with Data Fetching', + description: 'Added ability to fetch data from URLs directly in Object Editor with mobile-optimized interface' + }, + { + pattern: /complete.*postman.*table.*view/i, + type: 'feature', + title: 'Postman-Style Table View', + description: 'New professional table visualization with consistent design and advanced data exploration features' + }, + { + pattern: /enhanced.*mindmap.*visualization/i, + type: 'feature', + title: 'Professional Mindmap Visualization', + description: 'Beautiful mindmap interface for visualizing complex data structures with interactive navigation' + }, + { + pattern: /add.*text.*length.*checker/i, + type: 'feature', + title: 'Text Analysis Tool', + description: 'New comprehensive text analysis tool with length checking and detailed text statistics' + }, + { + pattern: /fix.*php.*serialization.*long.*text/i, + type: 'fix', + title: 'PHP Serialization Improvements', + description: 'Fixed PHP serialization handling and added support for long text fields in Visual Editor' + }, + { + pattern: /enhanced.*developer.*tools.*ux/i, + type: 'enhancement', + title: 'Developer Tools UX Enhancement', + description: 'Improved overall user experience with visual enhancements and better tool organization' + } + ]; + + for (const transform of transformations) { + if (transform.pattern.test(message)) { + return { + type: transform.type, + title: transform.title, + description: transform.description + }; + } + } + + // Fallback for unmatched patterns + if (message.includes('🐛') || message.toLowerCase().includes('fix')) { + return { + type: 'fix', + title: 'Bug Fixes', + description: message.replace(/🐛|fix/gi, '').trim() + }; + } + + if (message.includes('✨') || message.toLowerCase().includes('feat')) { + return { + type: 'feature', + title: 'New Feature', + description: message.replace(/✨|feat:/gi, '').trim() + }; + } + + return null; + }; + + // Get type icon and color + const getTypeConfig = (type) => { + const configs = { + feature: { + icon: , + color: 'text-blue-600 dark:text-blue-400', + bgColor: 'bg-blue-100 dark:bg-blue-900/20', + label: 'New Feature' + }, + enhancement: { + icon: , + color: 'text-purple-600 dark:text-purple-400', + bgColor: 'bg-purple-100 dark:bg-purple-900/20', + label: 'Enhancement' + }, + fix: { + icon: , + color: 'text-green-600 dark:text-green-400', + bgColor: 'bg-green-100 dark:bg-green-900/20', + label: 'Bug Fix' + }, + security: { + icon: , + color: 'text-red-600 dark:text-red-400', + bgColor: 'bg-red-100 dark:bg-red-900/20', + label: 'Security' + } + }; + return configs[type] || configs.enhancement; + }; + + // Group releases by date + const groupReleasesByDate = (releases) => { + const grouped = {}; + releases.forEach(release => { + const date = new Date(release.date).toDateString(); + if (!grouped[date]) { + grouped[date] = []; + } + grouped[date].push(release); + }); + return grouped; + }; + + const toggleRelease = (date) => { + const newExpanded = new Set(expandedReleases); + if (newExpanded.has(date)) { + newExpanded.delete(date); + } else { + newExpanded.add(date); + } + setExpandedReleases(newExpanded); + }; + + useEffect(() => { + // Simulate fetching commit data (in real app, this would be an API call) + const commitData = [ + { + hash: 'new2024', + date: '2025-09-24T18:57:18+07:00', + message: 'feat: Enhanced What\'s New feature with NON_TOOLS category and global footer' + }, + { + hash: '21d0406e', + date: '2025-09-24T14:05:10+07:00', + message: 'Improve ObjectEditor and PostmanTable UI/UX' + }, + { + hash: '57655410', + date: '2025-09-24T01:15:20+07:00', + message: 'feat: optimize analytics and mobile UI improvements' + }, + { + hash: '2e67a2bc', + date: '2025-09-24T00:12:28+07:00', + message: 'feat: comprehensive SEO optimization and GDPR compliance' + }, + { + hash: '977e784d', + date: '2025-09-23T14:17:13+07:00', + message: 'Improve ObjectEditor and Add TableEditor' + }, + { + hash: 'e1c74e4a', + date: '2025-09-21T16:33:28+07:00', + message: '✨ Enhanced Object Editor with fetch data & mobile improvements' + }, + { + hash: '12d45590', + date: '2025-09-21T15:09:17+07:00', + message: '🎯 Complete Postman-Style Table View with Consistent Design' + }, + { + hash: '82d14622', + date: '2025-09-21T07:09:33+07:00', + message: '✨ Enhanced mindmap visualization with professional UI' + }, + { + hash: '6f5bdf5f', + date: '2025-08-21T23:45:46+07:00', + message: 'Add Text Length Checker tool with comprehensive text analysis features' + }, + { + hash: '65cc3bc5', + date: '2025-08-21T23:19:22+07:00', + message: 'Fix PHP serialization and add Long Text type to Visual Editor' + }, + { + hash: '97459ea3', + date: '2025-08-07T20:05:11+07:00', + message: 'feat: Enhanced developer tools UX with visual improvements' + } + ]; + + const parsedReleases = commitData + .map(commit => { + const parsed = parseCommitMessage(commit.message); + if (!parsed) return null; + + return { + ...parsed, + date: commit.date, + hash: commit.hash + }; + }) + .filter(Boolean); + + setReleases(parsedReleases); + setLoading(false); + + // Auto-expand only the first (latest) release + const groupedByDate = groupReleasesByDate(parsedReleases); + const sortedDates = Object.keys(groupedByDate).sort((a, b) => new Date(b) - new Date(a)); + + const autoExpand = new Set(); + if (sortedDates.length > 0) { + autoExpand.add(sortedDates[0]); // Only expand the latest date + } + setExpandedReleases(autoExpand); + }, []); + + const groupedReleases = groupReleasesByDate(releases); + + return ( + +
+ {/* Header */} +
+
+ +
+

+ What's New +

+

+ Discover the latest features, improvements, and bug fixes that make your development workflow even better. +

+
+ + {loading ? ( +
+
+
+ ) : ( +
+ {/* Timeline line */} +
+ +
+ {Object.entries(groupedReleases) + .sort(([a], [b]) => new Date(b) - new Date(a)) + .map(([date, dayReleases], index) => { + const isExpanded = expandedReleases.has(date); + const releaseDate = new Date(date); + const isRecent = (new Date() - releaseDate) < 7 * 24 * 60 * 60 * 1000; + + return ( +
+ {/* Timeline dot */} +
+ +
+ {/* Date Header */} + + + {/* Release Items */} + {isExpanded && ( +
+ {dayReleases.map((release, index) => { + const typeConfig = getTypeConfig(release.type); + + return ( +
+
+
+
+ {typeConfig.icon} +
+
+
+
+

+ {release.title} +

+ + {typeConfig.label} + +
+

+ {release.description} +

+
+ + {new Date(release.date).toLocaleTimeString('en-US', { + hour: '2-digit', + minute: '2-digit' + })} + + #{release.hash} +
+
+
+
+ ); + })} +
+ )} +
+
+ ); + })} +
+
+ )} + + {/* Footer */} +
+

+ Stay tuned for more exciting updates and improvements! +

+
+
+
+ ); +}; + +export default ReleaseNotes; diff --git a/src/pages/TableEditor.js b/src/pages/TableEditor.js index fd57b83f..12b667ca 100644 --- a/src/pages/TableEditor.js +++ b/src/pages/TableEditor.js @@ -51,6 +51,8 @@ const TableEditor = () => { const [originalFileName, setOriginalFileName] = useState(""); // For export naming const [isTableFullscreen, setIsTableFullscreen] = useState(false); // For fullscreen table view const [frozenColumns, setFrozenColumns] = useState(0); // Number of columns to freeze on horizontal scroll + const [columnWidths, setColumnWidths] = useState({}); // Store custom column widths + const [resizing, setResizing] = useState(null); // Track which column is being resized const [showClearConfirmModal, setShowClearConfirmModal] = useState(false); // For clear confirmation modal const [showInputChangeModal, setShowInputChangeModal] = useState(false); // For input method change confirmation const [pendingTabChange, setPendingTabChange] = useState(null); // Store pending tab change @@ -1162,6 +1164,40 @@ const TableEditor = () => { setData([...data, newRow]); }; + // Column resize functions + const getColumnWidth = (columnId) => { + return columnWidths[columnId] || 150; // Default width + }; + + const handleResizeStart = (e, columnId) => { + e.preventDefault(); + const startX = e.clientX; + const startWidth = getColumnWidth(columnId); + + setResizing({ columnId, startX, startWidth }); + + const handleMouseMove = (e) => { + if (!resizing && resizing?.columnId === columnId) return; + + const deltaX = e.clientX - startX; + const newWidth = Math.max(50, startWidth + deltaX); // Minimum width of 50px + + setColumnWidths(prev => ({ + ...prev, + [columnId]: newWidth + })); + }; + + const handleMouseUp = () => { + setResizing(null); + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; + + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + }; + // Add new column const addColumn = () => { const newColumnId = `col_${Date.now()}`; @@ -2185,11 +2221,12 @@ const TableEditor = () => { 0 - ? "sticky left-0 z-20 bg-blue-50 dark:!bg-blue-900 w-12" - : "w-12" + ? "sticky left-0 z-20 bg-blue-50 dark:!bg-blue-900" + : "" }`} + style={{ width: '40px', maxWidth: '40px', minWidth: '40px' }} > { {columns.map((column, index) => { const isFrozen = index < frozenColumns; const leftOffset = isFrozen - ? 45 + index * 150 // 45px for checkbox column + 150px per frozen column (no gap) + ? 40 + columns.slice(0, index).reduce((acc, col) => acc + getColumnWidth(col.id), 0) : 0; return (
{
+ + {/* Resize handle */} +
handleResizeStart(e, column.id)} + title="Drag to resize column" + /> ); })} @@ -2310,11 +2353,12 @@ const TableEditor = () => { className="hover:bg-gray-50 dark:hover:bg-gray-700" > 0 - ? "sticky left-0 z-10 bg-blue-50 dark:!bg-blue-900 w-12" - : "w-12" + ? "sticky left-0 z-10 bg-blue-50 dark:!bg-blue-900" + : "" }`} + style={{ width: '40px', maxWidth: '40px', minWidth: '40px' }} > { {columns.map((column, index) => { const isFrozen = index < frozenColumns; const leftOffset = isFrozen - ? 45 + index * 150 // 45px for checkbox column + 150px per frozen column (no gap) + ? 40 + columns.slice(0, index).reduce((acc, col) => acc + getColumnWidth(col.id), 0) : 0; return ( {editingCell?.rowId === row.id && editingCell?.columnId === column.id ? ( @@ -2478,24 +2521,19 @@ const TableEditor = () => { {/* System Row - Add Row */} - {/* Sticky Add Row button on the left */} - + - {/* Empty cells to fill the rest of the row */} - - {/* Empty space for visual consistency */} - diff --git a/src/pages/TermsOfService.js b/src/pages/TermsOfService.js index 6d4589b9..8ec523f3 100644 --- a/src/pages/TermsOfService.js +++ b/src/pages/TermsOfService.js @@ -155,13 +155,6 @@ const TermsOfService = () => {
- - {/* Footer */} -
-

- © {SITE_CONFIG.year} {SITE_CONFIG.title} • Built with ❤️ for developers worldwide -

-
);