feat: optimised about and contact page

This commit is contained in:
siujamo
2026-01-16 09:56:48 +08:00
parent 71239b1d1b
commit 6e97243b94
2 changed files with 178 additions and 171 deletions
+62 -46
View File
@@ -1,107 +1,123 @@
/**
* About page component that displays information about the application.
* About page component that displays information about the JSON Visualiser application.
*/
export default function About() {
return (
<div className="space-y-8">
<div className="space-y-8 max-w-6xl mx-auto">
{/* Page Header */}
<div className="text-center">
<h1 className="text-3xl font-bold text-gray-900 sm:text-4xl">
About This Template
</h1>
<h1 className="text-3xl font-bold text-gray-900 sm:text-4xl">About JSON Visualiser</h1>
<p className="mt-4 text-lg text-gray-600">
Learn more about the technologies and architecture behind this React Router template.
A powerful, privacy-focused tool for debugging and visualising complex JSON data
structures.
</p>
</div>
{/* Content Sections */}
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
{/* Technology Stack */}
<div className="bg-white shadow rounded-lg p-6">
<h2 className="text-xl font-semibold text-gray-900 mb-4">
Technology Stack
<div className="bg-white shadow rounded-lg p-6 border border-gray-100">
<h2 className="text-xl font-semibold text-gray-900 mb-4 flex items-center">
<span className="mr-2">🛠</span> Technology Stack
</h2>
<ul className="space-y-3">
<li className="flex items-center">
<span className="w-2 h-2 bg-blue-500 rounded-full mr-3"></span>
<span className="text-gray-700"><strong>React 19</strong> - Latest version with modern features</span>
<span className="text-gray-700">
<strong>React 19 & TS</strong> - Type-safe UI components
</span>
</li>
<li className="flex items-center">
<span className="w-2 h-2 bg-blue-500 rounded-full mr-3"></span>
<span className="text-gray-700"><strong>TypeScript</strong> - Type-safe development</span>
<span className="text-gray-700">
<strong>jsonpath</strong> - Robust query engine for data extraction
</span>
</li>
<li className="flex items-center">
<span className="w-2 h-2 bg-blue-500 rounded-full mr-3"></span>
<span className="text-gray-700"><strong>React Router v7</strong> - Client-side routing</span>
<span className="text-gray-700">
<strong>Tailwind CSS</strong> - Modern, responsive styling
</span>
</li>
<li className="flex items-center">
<span className="w-2 h-2 bg-blue-500 rounded-full mr-3"></span>
<span className="text-gray-700"><strong>Tailwind CSS</strong> - Utility-first styling</span>
</li>
<li className="flex items-center">
<span className="w-2 h-2 bg-blue-500 rounded-full mr-3"></span>
<span className="text-gray-700"><strong>Redux Toolkit</strong> - State management</span>
</li>
<li className="flex items-center">
<span className="w-2 h-2 bg-blue-500 rounded-full mr-3"></span>
<span className="text-gray-700"><strong>Vite</strong> - Fast build tool and dev server</span>
<span className="text-gray-700">
<strong>Vite</strong> - Optimised build pipeline and dev experience
</span>
</li>
</ul>
</div>
{/* Features */}
<div className="bg-white shadow rounded-lg p-6">
<h2 className="text-xl font-semibold text-gray-900 mb-4">
Key Features
<div className="bg-white shadow rounded-lg p-6 border border-gray-100">
<h2 className="text-xl font-semibold text-gray-900 mb-4 flex items-center">
<span className="mr-2">🚀</span> Key Features
</h2>
<ul className="space-y-3">
<li className="flex items-center">
<span className="w-2 h-2 bg-green-500 rounded-full mr-3"></span>
<span className="text-gray-700">Modern React Router implementation</span>
<span className="text-gray-700">
Interactive <strong>collapsible</strong> tree navigation
</span>
</li>
<li className="flex items-center">
<span className="w-2 h-2 bg-green-500 rounded-full mr-3"></span>
<span className="text-gray-700">Protected routes with authentication</span>
<span className="text-gray-700">
Real-time JSONPath field <strong>highlighting</strong>
</span>
</li>
<li className="flex items-center">
<span className="w-2 h-2 bg-green-500 rounded-full mr-3"></span>
<span className="text-gray-700">Error boundary and error pages</span>
<span className="text-gray-700">One-click copy for matched results</span>
</li>
<li className="flex items-center">
<span className="w-2 h-2 bg-green-500 rounded-full mr-3"></span>
<span className="text-gray-700">Responsive design with Tailwind</span>
</li>
<li className="flex items-center">
<span className="w-2 h-2 bg-green-500 rounded-full mr-3"></span>
<span className="text-gray-700">TypeScript for type safety</span>
</li>
<li className="flex items-center">
<span className="w-2 h-2 bg-green-500 rounded-full mr-3"></span>
<span className="text-gray-700">ESLint and Prettier configuration</span>
<span className="text-gray-700">Zero-latency local processing</span>
</li>
</ul>
</div>
</div>
{/* Privacy Commitment */}
<div className="bg-indigo-50 border border-indigo-100 rounded-lg p-6 text-indigo-900">
<h2 className="text-xl font-semibold mb-3 flex items-center">
<span className="mr-2">🔒</span> Privacy & Data Security
</h2>
<p className="leading-relaxed">
We believe that your data belongs to you. This application is designed as a{" "}
<strong>purely client-side tool</strong>. All JSON parsing, path evaluation, and visual
rendering are performed locally within your browser. No data is ever uploaded to any
server, ensuring that sensitive configuration or user data remains entirely private.
</p>
</div>
{/* Architecture Overview */}
<div className="bg-white shadow rounded-lg p-6">
<h2 className="text-xl font-semibold text-gray-900 mb-4">
Architecture Overview
<h2 className="text-xl font-semibold text-gray-900 mb-4 flex items-center">
<span className="mr-2">🏗</span> Architecture Overview
</h2>
<div className="prose max-w-none text-gray-700">
<p className="mb-4">
This template follows modern React development practices with a clear separation of concerns:
The application follows a modular React architecture focused on performance and
maintainability:
</p>
<ul className="list-disc list-inside space-y-2 mb-4">
<li><strong>Components:</strong> Reusable UI components organised by feature</li>
<li><strong>Pages:</strong> Route-level components that represent different views</li>
<li><strong>Layouts:</strong> Wrapper components that provide consistent structure</li>
<li><strong>Store:</strong> Redux Toolkit slices for state management</li>
<li><strong>Router:</strong> Centralised routing configuration</li>
<li>
<strong>Recursive Renderer:</strong> A high-performance component tree that handles
massive JSON objects without blocking the main thread.
</li>
<li>
<strong>JSONPath Integration:</strong> Standardised path evaluation using the{" "}
<code>jsonpath</code> library, ensuring cross-platform query compatibility.
</li>
<li>
<strong>State Management:</strong> Efficient use of React hooks and useMemo to ensure
real-time UI updates during text entry.
</li>
</ul>
<p>
The routing system uses React Router&apos;s latest data router approach with <code>createBrowserRouter</code>,
providing better performance and developer experience compared to the legacy BrowserRouter approach.
Hosted on Vercel, this visualiser leverages modern edge deployment whilst strictly
adhering to the local-first data processing principle.
</p>
</div>
</div>
+114 -123
View File
@@ -1,130 +1,92 @@
import React from "react"
/**
* Contact page component that displays contact information and a contact form.
* Contact page component that encourages manual GitHub Issue submission.
*/
export default function Contact() {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
const owner = "onixbyte"
const repo = "json-visualiser"
const handleRedirect = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
// Handle form submission logic here
alert("Thank you for your message! This is a demo form.")
const formData = new FormData(e.currentTarget)
const subject = formData.get("subject") as string
const name = formData.get("name") as string
const email = formData.get("email") as string
const message = formData.get("message") as string
const type = formData.get("type") as string
// Construct a professional body template for the GitHub issue
const issueBody = `
### Description
${message}
---
*Generated via JSON Visualiser Contact Page*
`.trim()
const githubUrl = `https://github.com/${owner}/${repo}/issues/new?title=${encodeURIComponent(
`[${type == "help wanted" ? "General Enquiry" : (type == "enhancement" ? "Feature request" : "Bug")}] ${subject}`
)}&body=${encodeURIComponent(issueBody)}&labels=${type}`
// Open in a new tab so they don't lose their place on your site
window.open(githubUrl, "_blank", "noopener,noreferrer")
}
return (
<div className="space-y-8">
{/* Page Header */}
<div className="text-center">
<h1 className="text-3xl font-bold text-gray-900 sm:text-4xl">
Get in Touch
</h1>
<div className="max-w-5xl mx-auto py-12 px-4 sm:px-6">
{/* Header */}
<div className="text-center mb-12">
<h1 className="text-3xl font-bold text-gray-900 sm:text-4xl">Get in Touch</h1>
<p className="mt-4 text-lg text-gray-600">
Have questions about this template? We&apos;d love to hear from you.
The best way to reach us is via our GitHub repository.
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{/* Contact Information */}
<div className="bg-white shadow rounded-lg p-6">
<h2 className="text-xl font-semibold text-gray-900 mb-6">
Contact Information
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 items-start">
{/* Left Side: Information */}
<div className="space-y-8">
<section>
<h2 className="text-xl font-semibold text-gray-900 mb-4 flex items-center">
<span className="mr-2">🤝</span> Why GitHub Issues?
</h2>
<p className="text-gray-600 leading-relaxed">
We use GitHub to track all bug reports and feature requests. This ensures our
development process remains **transparent** and that your feedback is properly
prioritised by the community.
</p>
</section>
<div className="space-y-4">
{/* Email */}
<div className="flex items-center">
<div className="flex-shrink-0">
<svg className="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
<div className="ml-3">
<p className="text-sm font-medium text-gray-900">Email</p>
<p className="text-sm text-gray-600">zihlu.wang@outlook.com</p>
</div>
</div>
<section className="bg-blue-50 border border-blue-100 p-6 rounded-2xl">
<h3 className="text-blue-900 font-bold mb-2">How it works:</h3>
<ol className="list-decimal list-inside text-blue-800 text-sm space-y-2">
<li>Fill in the enquiry details in the form provided.</li>
<li>
Click <strong>"Prepare GitHub Issue"</strong>.
</li>
<li>You will be redirected to GitHub with the data pre-filled.</li>
<li>
Simply hit <strong>"Submit new issue"</strong> on their site.
</li>
</ol>
</section>
{/* GitHub */}
<div className="flex items-center">
<div className="flex-shrink-0">
<svg className="h-6 w-6 text-gray-400" fill="currentColor" viewBox="0 0 24 24">
<path fillRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<p className="text-sm font-medium text-gray-900"><a href="https://github.com/onixbyte/react-template">GitHub</a></p>
<p className="text-sm text-gray-600">github.com/onixbyte/react-template</p>
</div>
</div>
{/* Documentation */}
<div className="flex items-center">
<div className="flex-shrink-0">
<svg className="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
</div>
<div className="ml-3">
<p className="text-sm font-medium text-gray-900">Documentation</p>
<p className="text-sm text-gray-600">Check the README.md file</p>
</div>
</div>
</div>
{/* Quick Links */}
<div className="mt-8">
<h3 className="text-lg font-medium text-gray-900 mb-4">Quick Links</h3>
<div className="space-y-2">
<a href="https://reactrouter.com" target="_blank" rel="noopener noreferrer" className="block text-blue-600 hover:text-blue-800 text-sm">
React Router Documentation
<div className="pt-4 border-t border-gray-100">
<p className="text-sm text-gray-500 italic">
Alternatively, you can email us directly at: <br />
<a
href="mailto:real@zihluwang.me"
className="text-blue-600 font-medium hover:underline">
real@zihluwang.me
</a>
<a href="https://tailwindcss.com" target="_blank" rel="noopener noreferrer" className="block text-blue-600 hover:text-blue-800 text-sm">
Tailwind CSS Documentation
</a>
<a href="https://vitejs.dev" target="_blank" rel="noopener noreferrer" className="block text-blue-600 hover:text-blue-800 text-sm">
Vite Documentation
</a>
</div>
</p>
</div>
</div>
{/* Contact Form */}
<div className="bg-white shadow rounded-lg p-6">
<h2 className="text-xl font-semibold text-gray-900 mb-6">
Send us a Message
</h2>
<form onSubmit={handleSubmit} className="space-y-4">
{/* Name */}
<div>
<label htmlFor="name" className="block text-sm font-medium text-gray-700 mb-1">
Name
</label>
<input
type="text"
id="name"
name="name"
required
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Your full name"
/>
</div>
{/* Email */}
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-1">
Email
</label>
<input
type="email"
id="email"
name="email"
required
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="your.email@example.com"
/>
</div>
{/* Subject */}
{/* Right Side: Form */}
<div className="bg-white shadow-xl shadow-gray-200/50 border border-gray-100 rounded-2xl p-8">
<form onSubmit={handleRedirect} className="space-y-5">
<div>
<label htmlFor="subject" className="block text-sm font-medium text-gray-700 mb-1">
Subject
@@ -134,35 +96,64 @@ export default function Contact() {
id="subject"
name="subject"
required
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="What is this about?"
className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:bg-white outline-none transition-all"
placeholder="Bug report / Feature request"
/>
</div>
{/* Message */}
<div>
<label
htmlFor="type"
className="block text-sm font-semibold text-gray-700 mb-1.5 ml-1">
Enquiry Type
</label>
<div className="relative group">
<select
id="type"
name="type"
required
className="w-full appearance-none px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-gray-700 text-sm cursor-pointer transition-all duration-200 hover:border-gray-300 hover:bg-gray-100/50 focus:ring-4 focus:ring-indigo-500/10 focus:border-indigo-500 focus:bg-white outline-none">
<option value="help wanted">General Enquiry</option>
<option value="enhancement">Feature Request</option>
<option value="bug">Bug</option>
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-gray-400 group-hover:text-gray-600 transition-colors">
<svg
className="h-4 w-4 fill-current"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20">
<path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
</svg>
</div>
</div>
<p className="mt-2 ml-1 text-[11px] text-gray-400">
Selecting a type helps us categorise and prioritise your issue.
</p>
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium text-gray-700 mb-1">
Message
Message Details
</label>
<textarea
id="message"
name="message"
rows={4}
required
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Tell us more about your question or feedback..."
className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:bg-white outline-none transition-all resize-none"
placeholder="Describe your enquiry here..."
/>
</div>
{/* Submit Button */}
<div>
<button
type="submit"
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Send Message
</button>
</div>
<button
type="submit"
className="w-full flex items-center justify-center py-3 px-4 rounded-xl text-white font-bold bg-gray-900 hover:bg-gray-800 transition-all shadow-lg">
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 21.795 24 17.297 24 12.017c0-6.627-5.373-12-12-12" />
</svg>
Prepare GitHub Issue
</button>
</form>
</div>
</div>