Skip to content

Commit 545a301

Browse files
committed
feat: apps.json
1 parent 1a8ecbd commit 545a301

File tree

5 files changed

+188
-125
lines changed

5 files changed

+188
-125
lines changed

public/apps/apps.json

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
[
2+
{
3+
"slug": "image-toolkit",
4+
"to": "/apps/image-toolkit",
5+
"title": "Image Toolkit",
6+
"description": "A toolkit for basic image manipulations.",
7+
"icon": "Image"
8+
},
9+
{
10+
"slug": "codename-generator",
11+
"to": "/apps/codename-generator",
12+
"title": "Codename Generator",
13+
"description": "Generate cool, spy-ish project names.",
14+
"icon": "ShieldCheck"
15+
},
16+
{
17+
"slug": "picker-wheel",
18+
"to": "/apps/picker-wheel",
19+
"title": "Picker Wheel",
20+
"description": "A spinning wheel to pick a random winner from a list of entries.",
21+
"icon": "CircleDashed"
22+
},
23+
{
24+
"slug": "tournament-bracket",
25+
"to": "/apps/tournament-bracket",
26+
"title": "Tournament Bracket",
27+
"description": "Create and manage tournament brackets.",
28+
"icon": "ListNumbers"
29+
},
30+
{
31+
"slug": "fantasy-name-generator",
32+
"to": "/apps/fantasy-name-generator",
33+
"title": "Fantasy Name Generator",
34+
"description": "Generate fantasy names for characters, places, and items.",
35+
"icon": "Sparkle"
36+
},
37+
{
38+
"slug": "dice-roller",
39+
"to": "/apps/dice-roller",
40+
"title": "Dice Roller",
41+
"description": "Roll various types of dice for your games and adventures.",
42+
"icon": "DiceSix"
43+
},
44+
{
45+
"slug": "word-counter",
46+
"to": "/apps/word-counter",
47+
"title": "Word Counter",
48+
"description": "Count words, characters, lines and paragraphs in a text.",
49+
"icon": "TextT"
50+
},
51+
{
52+
"slug": "case-converter",
53+
"to": "/apps/case-converter",
54+
"title": "Case Converter",
55+
"description": "Convert text to different cases (e.g., uppercase, lowercase, camelCase).",
56+
"icon": "TextAa"
57+
},
58+
{
59+
"slug": "base64-converter",
60+
"to": "/apps/base64-converter",
61+
"title": "Base64 Converter",
62+
"description": "Encode and decode text to and from Base64 format.",
63+
"icon": "Code"
64+
},
65+
{
66+
"slug": "url-converter",
67+
"to": "/apps/url-converter",
68+
"title": "URL Encoder/Decoder",
69+
"description": "Encode and decode URL strings.",
70+
"icon": "LinkIcon"
71+
},
72+
{
73+
"slug": "ascii-converter",
74+
"to": "/apps/ascii-converter",
75+
"title": "Text to ASCII Converter",
76+
"description": "Convert text to ASCII codes and vice-versa.",
77+
"icon": "Keyboard"
78+
},
79+
{
80+
"slug": "hash-generator",
81+
"to": "/apps/hash-generator",
82+
"title": "Hash Generator",
83+
"description": "Generate SHA1, SHA256, and SHA512 hashes from text.",
84+
"icon": "Fingerprint"
85+
},
86+
{
87+
"slug": "uuid-generator",
88+
"to": "/apps/uuid-generator",
89+
"title": "UUID Generator",
90+
"description": "Generate UUID v4.",
91+
"icon": "Key"
92+
},
93+
{
94+
"slug": "password-generator",
95+
"to": "/apps/password-generator",
96+
"title": "Password Generator",
97+
"description": "Generate strong, random passwords with customizable options.",
98+
"icon": "Key"
99+
},
100+
{
101+
"slug": "json-formatter",
102+
"to": "/apps/json-formatter",
103+
"title": "JSON Formatter & Validator",
104+
"description": "Format and validate JSON data for readability and correctness.",
105+
"icon": "Code"
106+
},
107+
{
108+
"slug": "color-contrast-checker",
109+
"to": "/apps/color-contrast-checker",
110+
"title": "Color Contrast Checker",
111+
"description": "Check WCAG color contrast ratios for accessibility.",
112+
"icon": "Palette"
113+
},
114+
{
115+
"slug": "qr-code-generator",
116+
"to": "/apps/qr-code-generator",
117+
"title": "QR Code Generator",
118+
"description": "Generate QR codes from text or URLs with customizable versions and error correction.",
119+
"icon": "QrCode"
120+
},
121+
{
122+
"slug": "color-palette-generator",
123+
"to": "/apps/color-palette-generator",
124+
"title": "Color Palette Generator",
125+
"description": "Generate random color palettes.",
126+
"icon": "Palette"
127+
},
128+
{
129+
"slug": "css-unit-converter",
130+
"to": "/apps/css-unit-converter",
131+
"title": "CSS Unit Converter",
132+
"description": "Convert between px, em, rem, vw, vh, and % units.",
133+
"icon": "Ruler"
134+
}
135+
]

src/components/AppCard.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import React from 'react';
22
import { Link } from 'react-router-dom';
33
import { ArrowRight } from '@phosphor-icons/react';
44
import colors from '../config/colors';
5+
import { appIcons } from '../utils/appIcons';
56

67
const AppCard = ({ app }) => {
7-
const { to, title, description, icon: Icon } = app;
8+
const { to, title, description } = app;
9+
const Icon = appIcons[app.icon];
810

911
const cardStyle = {
1012
backgroundColor: colors['app-alpha-10'],

src/components/Search.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,23 @@ const Search = ({ isVisible }) => {
66
const [searchTerm, setSearchTerm] = useState('');
77
const [searchResults, setSearchResults] = useState([]);
88
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
9-
const [data, setData] = useState({ posts: [], projects: [], logs: [], routes: [] }); // Add routes to data
9+
const [data, setData] = useState({ posts: [], projects: [], logs: [], routes: [], apps: [] }); // Add routes to data
1010
const searchRef = useRef(null);
1111

1212
useEffect(() => {
1313
const fetchData = async () => {
1414
try {
15-
const [postsRes, projectsRes, logsRes] = await Promise.all([
15+
const [postsRes, projectsRes, logsRes, appsRes] = await Promise.all([
1616
fetch('/posts/posts.json'),
1717
fetch('/projects/projects.json'),
1818
fetch('/logs/logs.json'),
19+
fetch('/apps/apps.json'),
1920
]);
2021

2122
const posts = await postsRes.json();
2223
const projects = await projectsRes.json();
2324
const logs = await logsRes.json();
25+
const apps = await appsRes.json();
2426

2527
const allPosts = posts.flatMap(item =>
2628
item.series ? item.series.posts.map(p => ({ ...p, series: item.title })) : item
@@ -39,7 +41,7 @@ const Search = ({ isVisible }) => {
3941
{ title: 'Random', slug: '/random', type: 'route' },
4042
];
4143

42-
setData({ posts: allPosts, projects, logs, routes }); // Include routes in data
44+
setData({ posts: allPosts, projects: projects, logs: logs, routes: routes, apps: apps }); // Include routes in data
4345
} catch (error) {
4446
console.error('Failed to fetch search data:', error);
4547
}
@@ -85,7 +87,16 @@ const Search = ({ isVisible }) => {
8587
)
8688
.map((route) => ({ ...route, type: 'route' }));
8789

88-
setSearchResults([...posts, ...projects, ...logs, ...routes]); // Include routes in search results
90+
// Filter apps
91+
const apps = data.apps
92+
.filter(
93+
(app) =>
94+
app.title.toLowerCase().includes(lowerCaseSearchTerm) ||
95+
app.slug.toLowerCase().includes(lowerCaseSearchTerm)
96+
)
97+
.map((app) => ({ ...app, type: 'app' }));
98+
99+
setSearchResults([...posts, ...projects, ...logs, ...routes, ...apps]); // Include routes in search results
89100
setIsDropdownOpen(true);
90101
} else {
91102
setSearchResults([]);
@@ -116,6 +127,8 @@ const Search = ({ isVisible }) => {
116127
return `/logs/${result.slug}`;
117128
case 'route': // Handle routes
118129
return result.slug;
130+
case 'app': // Handle apps
131+
return result.slug;
119132
default:
120133
return '/';
121134
}
@@ -136,7 +149,9 @@ const Search = ({ isVisible }) => {
136149
onFocus={() => setIsDropdownOpen(true)}
137150
className="bg-gray-800 text-white w-full py-2 px-4 pl-10 focus:outline-none focus:ring-2 focus:ring-primary-400 rounded-md"
138151
/>
139-
<MagnifyingGlassIcon className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400" />
152+
<MagnifyingGlassIcon
153+
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"
154+
/>
140155
{isDropdownOpen && searchResults.length > 0 && (
141156
<div className="absolute mt-2 w-full max-w-md max-h-96 overflow-y-auto bg-gray-800 border border-gray-700 rounded-md shadow-lg z-50 left-1/2 -translate-x-1/2">
142157
<ul>

src/pages/AppPage.js

Lines changed: 10 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,19 @@
1-
import React from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import { Link } from 'react-router-dom';
3-
import { ArrowLeftIcon, ListNumbers, Sparkle, TextT, TextAa, Code, Link as LinkIcon, Keyboard, Fingerprint, Key, Palette, Ruler, DiceSix, CircleDashed, ShieldCheck, Image, QrCode } from '@phosphor-icons/react';
3+
import { ArrowLeftIcon } from '@phosphor-icons/react';
44
import AppCard from '../components/AppCard';
55
import usePageTitle from '../utils/usePageTitle';
66

7-
const apps = [
8-
{
9-
to: '/apps/image-toolkit',
10-
title: 'Image Toolkit',
11-
description: 'A toolkit for basic image manipulations.',
12-
icon: Image,
13-
},
14-
{
15-
to: '/apps/codename-generator',
16-
title: 'Codename Generator',
17-
description: 'Generate cool, spy-ish project names.',
18-
icon: ShieldCheck,
19-
},
20-
{
21-
to: '/apps/picker-wheel',
22-
title: 'Picker Wheel',
23-
description: 'A spinning wheel to pick a random winner from a list of entries.',
24-
icon: CircleDashed,
25-
},
26-
{
27-
to: '/apps/tournament-bracket',
28-
title: 'Tournament Bracket',
29-
description: 'Create and manage tournament brackets.',
30-
icon: ListNumbers,
31-
},
32-
{
33-
to: '/apps/fantasy-name-generator',
34-
title: 'Fantasy Name Generator',
35-
description: 'Generate fantasy names for characters, places, and items.',
36-
icon: Sparkle,
37-
},
38-
{
39-
to: '/apps/dice-roller',
40-
title: 'Dice Roller',
41-
description: 'Roll various types of dice for your games and adventures.',
42-
icon: DiceSix,
43-
},
44-
{
45-
to: '/apps/word-counter',
46-
title: 'Word Counter',
47-
description: 'Count words, characters, lines and paragraphs in a text.',
48-
icon: TextT,
49-
},
50-
{
51-
to: '/apps/case-converter',
52-
title: 'Case Converter',
53-
description: 'Convert text to different cases (e.g., uppercase, lowercase, camelCase).',
54-
icon: TextAa,
55-
},
56-
{
57-
to: '/apps/base64-converter',
58-
title: 'Base64 Converter',
59-
description: 'Encode and decode text to and from Base64 format.',
60-
icon: Code,
61-
},
62-
{
63-
to: '/apps/url-converter',
64-
title: 'URL Encoder/Decoder',
65-
description: 'Encode and decode URL strings.',
66-
icon: LinkIcon,
67-
},
68-
{
69-
to: '/apps/ascii-converter',
70-
title: 'Text to ASCII Converter',
71-
description: 'Convert text to ASCII codes and vice-versa.',
72-
icon: Keyboard,
73-
},
74-
{
75-
to: '/apps/hash-generator',
76-
title: 'Hash Generator',
77-
description: 'Generate SHA1, SHA256, and SHA512 hashes from text.',
78-
icon: Fingerprint,
79-
},
80-
{
81-
to: '/apps/uuid-generator',
82-
title: 'UUID Generator',
83-
description: 'Generate UUID v4.',
84-
icon: Key,
85-
},
86-
{
87-
to: '/apps/password-generator',
88-
title: 'Password Generator',
89-
description: 'Generate strong, random passwords with customizable options.',
90-
icon: Key,
91-
},
92-
{
93-
to: '/apps/json-formatter',
94-
title: 'JSON Formatter & Validator',
95-
description: 'Format and validate JSON data for readability and correctness.',
96-
icon: Code,
97-
},
98-
{
99-
to: '/apps/color-contrast-checker',
100-
title: 'Color Contrast Checker',
101-
description: 'Check WCAG color contrast ratios for accessibility.',
102-
icon: Palette,
103-
},
104-
{
105-
to: '/apps/qr-code-generator',
106-
title: 'QR Code Generator',
107-
description: 'Generate QR codes from text or URLs with customizable versions and error correction.',
108-
icon: QrCode,
109-
},
110-
{
111-
to: '/apps/color-palette-generator',
112-
title: 'Color Palette Generator',
113-
description: 'Generate random color palettes.',
114-
icon: Palette,
115-
},
116-
{
117-
to: '/apps/css-unit-converter',
118-
title: 'CSS Unit Converter',
119-
description: 'Convert between px, em, rem, vw, vh, and % units.',
120-
icon: Ruler,
121-
},
122-
];
123-
1247
function AppPage() {
1258
usePageTitle('Apps');
9+
const [apps, setApps] = useState([]);
10+
11+
useEffect(() => {
12+
fetch('/apps/apps.json')
13+
.then((response) => response.json())
14+
.then((data) => setApps(data))
15+
.catch((error) => console.error('Error fetching apps:', error));
16+
}, []);
12617

12718
return (
12819
<div className="py-16 sm:py-24">

src/utils/appIcons.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ListNumbers, Sparkle, TextT, TextAa, Code, Link as LinkIcon, Keyboard, Fingerprint, Key, Palette, Ruler, DiceSix, CircleDashed, ShieldCheck, Image, QrCode } from '@phosphor-icons/react';
2+
3+
export const appIcons = {
4+
ListNumbers,
5+
Sparkle,
6+
TextT,
7+
TextAa,
8+
Code,
9+
Link: LinkIcon, // Use the aliased name for consistency
10+
Keyboard,
11+
Fingerprint,
12+
Key,
13+
Palette,
14+
Ruler,
15+
DiceSix,
16+
CircleDashed,
17+
ShieldCheck,
18+
Image,
19+
QrCode,
20+
};

0 commit comments

Comments
 (0)