feat: Enhanced What's New feature with NON_TOOLS category and global footer
✨ 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
This commit is contained in:
402
src/pages/ReleaseNotes.js
Normal file
402
src/pages/ReleaseNotes.js
Normal file
@@ -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: <Sparkles className="h-4 w-4" />,
|
||||
color: 'text-blue-600 dark:text-blue-400',
|
||||
bgColor: 'bg-blue-100 dark:bg-blue-900/20',
|
||||
label: 'New Feature'
|
||||
},
|
||||
enhancement: {
|
||||
icon: <Zap className="h-4 w-4" />,
|
||||
color: 'text-purple-600 dark:text-purple-400',
|
||||
bgColor: 'bg-purple-100 dark:bg-purple-900/20',
|
||||
label: 'Enhancement'
|
||||
},
|
||||
fix: {
|
||||
icon: <Bug className="h-4 w-4" />,
|
||||
color: 'text-green-600 dark:text-green-400',
|
||||
bgColor: 'bg-green-100 dark:bg-green-900/20',
|
||||
label: 'Bug Fix'
|
||||
},
|
||||
security: {
|
||||
icon: <Shield className="h-4 w-4" />,
|
||||
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 (
|
||||
<ToolLayout
|
||||
title="Release Notes"
|
||||
description="Stay updated with the latest features, improvements, and fixes"
|
||||
>
|
||||
<div className="max-w-4xl mx-auto">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-12">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br from-blue-500 to-purple-600 rounded-2xl mb-6">
|
||||
<Sparkles className="h-8 w-8 text-white" />
|
||||
</div>
|
||||
<h1 className="text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">
|
||||
What's New
|
||||
</h1>
|
||||
<p className="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
Discover the latest features, improvements, and bug fixes that make your development workflow even better.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center py-12">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="relative">
|
||||
{/* Timeline line */}
|
||||
<div className="absolute left-8 top-0 bottom-0 w-0.5 bg-gradient-to-b from-blue-500 via-purple-500 to-transparent"></div>
|
||||
|
||||
<div className="space-y-6">
|
||||
{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 (
|
||||
<div key={date} className="relative">
|
||||
{/* Timeline dot */}
|
||||
<div className="absolute left-6 top-6 w-4 h-4 bg-gradient-to-r from-blue-500 to-purple-500 rounded-full border-4 border-white dark:border-gray-900 shadow-lg z-10"></div>
|
||||
|
||||
<div className="ml-16 bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
|
||||
{/* Date Header */}
|
||||
<button
|
||||
onClick={() => toggleRelease(date)}
|
||||
className="w-full px-6 py-4 flex items-center justify-between hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors"
|
||||
>
|
||||
<div className="flex items-center space-x-3">
|
||||
<Calendar className="h-5 w-5 text-gray-500 dark:text-gray-400" />
|
||||
<div className="text-left">
|
||||
<h3 className="font-semibold text-gray-900 dark:text-gray-100">
|
||||
{releaseDate.toLocaleDateString('en-US', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
})}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
{dayReleases.length} update{dayReleases.length !== 1 ? 's' : ''}
|
||||
{isRecent && <span className="ml-2 text-blue-600 dark:text-blue-400">• Recent</span>}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{isExpanded ? (
|
||||
<ChevronUp className="h-5 w-5 text-gray-400" />
|
||||
) : (
|
||||
<ChevronDown className="h-5 w-5 text-gray-400" />
|
||||
)}
|
||||
</button>
|
||||
|
||||
{/* Release Items */}
|
||||
{isExpanded && (
|
||||
<div className="border-t border-gray-200 dark:border-gray-700">
|
||||
{dayReleases.map((release, index) => {
|
||||
const typeConfig = getTypeConfig(release.type);
|
||||
|
||||
return (
|
||||
<div key={release.hash} className={`p-6 ${index !== dayReleases.length - 1 ? 'border-b border-gray-100 dark:border-gray-700' : ''}`}>
|
||||
<div className="flex items-start space-x-4">
|
||||
<div className={`flex-shrink-0 p-2 rounded-lg ${typeConfig.bgColor}`}>
|
||||
<div className={typeConfig.color}>
|
||||
{typeConfig.icon}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center space-x-2 mb-2">
|
||||
<h4 className="font-semibold text-gray-900 dark:text-gray-100">
|
||||
{release.title}
|
||||
</h4>
|
||||
<span className={`px-2 py-1 text-xs font-medium rounded-full ${typeConfig.bgColor} ${typeConfig.color}`}>
|
||||
{typeConfig.label}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-gray-600 dark:text-gray-400 leading-relaxed">
|
||||
{release.description}
|
||||
</p>
|
||||
<div className="mt-3 flex items-center space-x-4 text-xs text-gray-500 dark:text-gray-400">
|
||||
<span>
|
||||
{new Date(release.date).toLocaleTimeString('en-US', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})}
|
||||
</span>
|
||||
<span>#{release.hash}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Footer */}
|
||||
<div className="text-center mt-12 py-8 border-t border-gray-200 dark:border-gray-700">
|
||||
<p className="text-gray-500 dark:text-gray-400">
|
||||
Stay tuned for more exciting updates and improvements!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</ToolLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReleaseNotes;
|
||||
Reference in New Issue
Block a user