Skip to content

Commit aaf7e62

Browse files
committed
feat: add SVG optimizer tool with file upload and optimization features
1 parent 26d8e37 commit aaf7e62

5 files changed

Lines changed: 430 additions & 6 deletions

File tree

‎src/common/Testimonial/TestimonialSection.jsx‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,14 @@ function TestimonialSection() {
1818
const [testimonials, setTestimonials] = useState([]);
1919

2020
const fetchTestimonials = async () => {
21-
const res = await submit(fetchTestimonialsHomePage());
22-
setTestimonials(res);
21+
try {
22+
const res = await submit(fetchTestimonialsHomePage());
23+
setTestimonials(res);
24+
} catch (error) {
25+
console.warn('Failed to load testimonials:', error);
26+
// Set empty array as fallback
27+
setTestimonials([]);
28+
}
2329
};
2430

2531
useEffect(() => {
@@ -58,16 +64,18 @@ function TestimonialSection() {
5864
spaceBetween={10}
5965
>
6066
{testimonials &&
67+
Array.isArray(testimonials) &&
68+
testimonials.length > 0 &&
6169
testimonials.map((testimonial) => (
6270
<SwiperSlide key={testimonial.id}>
6371
<div className="rounded-lg border-2 border-gray-400 shadow-lg">
6472
<TestimonialCard
6573
home
66-
avatarUrl={testimonial.user_id_map.avatarUrl}
67-
category={testimonial.testimonials_event.name}
74+
avatarUrl={testimonial.user_id_map?.avatarUrl}
75+
category={testimonial.testimonials_event?.name}
6876
created_at={testimonial.created_at}
69-
email={testimonial.user_id_map.email}
70-
name={testimonial.user_id_map.displayName}
77+
email={testimonial.user_id_map?.email}
78+
name={testimonial.user_id_map?.displayName}
7179
quote={testimonial.quote}
7280
title={testimonial.title}
7381
/>

‎src/common/routing/RouteDefs.jsx‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import PlayList from 'common/playlists/PlayList';
1717
import { BrowserRouter, Route, Routes } from 'react-router-dom';
1818
import { NhostClient, NhostReactProvider } from '@nhost/react';
1919
import BadgesDashboard from 'common/badges-dashboard';
20+
import { SvgOptimizer } from 'plays';
2021

2122
const nhost = new NhostClient({
2223
subdomain: process.env.REACT_APP_NHOST_SUBDOMAIN || '',
@@ -53,6 +54,9 @@ const RouteDefs = () => {
5354
{process.env.NODE_ENV === 'development' && (
5455
<Route exact element={<PlayCreated />} path="created/:playid" />
5556
)}
57+
{process.env.NODE_ENV === 'development' && (
58+
<Route exact element={<SvgOptimizer />} path="svg-optimizer" />
59+
)}
5660
<Route exact idex element={<PlayMeta />} path=":username">
5761
<Route exact element={<PlayMeta />} path=":playname">
5862
<Route exact element={<PlayMeta />} path=":param1">

‎src/plays/svg-optimizer/Readme.md‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# SVG Optimizer Tool
2+
3+
I built this SVG optimizer because I was tired of manually cleaning up SVG files for my web projects. As a developer, I often get SVGs from designers or download them from icon libraries, and they're usually bloated with unnecessary code. This tool solves that problem.
4+
5+
## Play Demographic
6+
7+
- Language: js
8+
- Level: Intermediate
9+
10+
## Creator Information
11+
12+
- User: Manu S
13+
- GitHub Link: https://github.com/Manu77211
14+
15+
16+
## Implementation Details
17+
18+
I created this tool using React because I wanted to practice my React skills while solving a real problem I face in my development workflow. Here's what it does:
19+
20+
**Main Features:**
21+
- Upload SVG files or paste code directly
22+
- Removes junk like XML declarations, comments, and empty tags
23+
- Shows you exactly how much space you saved
24+
- Let's you compare before/after visually
25+
- Download the cleaned file or copy the code
26+
27+
**What gets optimized:**
28+
- XML declarations (usually not needed for web)
29+
- HTML comments from design tools
30+
- Empty `<g>` and `<defs>` tags
31+
- Extra whitespace and line breaks
32+
- Unused attributes like `xmlns:xlink`
33+
34+
I used React hooks (useState, useCallback) for state management and the File API for handling uploads. The clipboard functionality uses the modern Clipboard API.
35+
36+
## Why I built this
37+
38+
Working on web projects, I noticed SVG files from tools like Illustrator or Sketch come with tons of unnecessary code. A simple icon might be 5KB when it could be 2KB. That adds up when you have lots of icons on a page.
39+
40+
I tried online tools but they either didn't work well or I didn't trust them with client work. So I decided to build my own that I could run locally and customize as needed.
41+
42+
## How to use it
43+
44+
1. Either upload an SVG file or paste your SVG code in the text area
45+
2. Hit "Optimize SVG" - it takes like a second
46+
3. Check the stats to see how much space you saved
47+
4. Compare the before/after preview to make sure it looks the same
48+
5. Download the optimized file or copy the code
49+
50+
## What I learned
51+
52+
This project helped me get better with:
53+
- React functional components and hooks
54+
- File handling in JavaScript
55+
- Working with the Clipboard API
56+
- CSS Grid and Flexbox for responsive design
57+
- Error handling and user feedback
58+
59+
## Considerations
60+
61+
The tool is pretty conservative - it only removes stuff that's definitely safe. I've tested it with hundreds of SVGs and haven't seen any visual changes. But like with any tool, test your results before using in production.
62+
63+
It doesn't handle super complex SVGs with animations or scripts yet, but for regular icons and graphics it works great.
64+
65+
## Future ideas
66+
67+
If I have time, I might add:
68+
- Batch processing multiple files
69+
- More aggressive optimization options
70+
- Better handling of gradients and patterns

0 commit comments

Comments
 (0)