Skip to content

Commit f41bf2f

Browse files
fix(string-inspector): fix input value vanish issue
1 parent fc41951 commit f41bf2f

File tree

2 files changed

+57
-68
lines changed

2 files changed

+57
-68
lines changed

client/src/components/tools/string-inspector.tsx

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,14 @@ export default function StringInspector() {
3737
};
3838

3939
const loadExample = () => {
40-
const example = `Hello, World!
40+
const example = `Hello, World! 🌍
4141
This is a sample text for analysis.
4242
It contains multiple lines, words, and characters.
43-
Let's see what the inspector reveals!`;
43+
Let's see what the inspector reveals! 🚀
44+
45+
Unicode characters: αβγδε, 你好世界, 🎉🎊🎈
46+
Special symbols: ©®™€£¥¢§¶†‡
47+
Emojis: 😀😃😄😁😆😅🤣😂🙂🙃😉😊😇`;
4448
updateState({ input: example });
4549
};
4650

@@ -51,10 +55,10 @@ Let's see what the inspector reveals!`;
5155
Characters (no spaces): ${analysis.charactersNoSpaces}
5256
Words: ${analysis.words}
5357
Lines: ${analysis.lines}
54-
Paragraphs: ${analysis.paragraphs}
5558
Sentences: ${analysis.sentences}
5659
Average words per sentence: ${analysis.averageWordsPerSentence.toFixed(2)}
57-
Most frequent character: "${analysis.mostFrequentChar}"`;
60+
Most frequent character: "${analysis.mostFrequentChar}"
61+
Byte size: ${analysis.byteSize} bytes`;
5862
};
5963

6064
return (
@@ -80,12 +84,11 @@ Most frequent character: "${analysis.mostFrequentChar}"`;
8084
value={input}
8185
onChange={(e) => {
8286
const newValue = e.target.value;
83-
updateState({ input: newValue });
8487
if (newValue) {
8588
const result = analyzeString(newValue);
86-
updateState({ analysis: result });
89+
updateState({ input: newValue, analysis: result });
8790
} else {
88-
updateState({ analysis: null });
91+
updateState({ input: newValue, analysis: null });
8992
}
9093
}}
9194
className="tool-textarea"
@@ -118,36 +121,20 @@ Most frequent character: "${analysis.mostFrequentChar}"`;
118121
<div className="text-2xl font-bold">{analysis.lines}</div>
119122
</div>
120123
<div className="p-3 bg-muted rounded-md">
121-
<div className="text-sm font-medium text-muted-foreground">Paragraphs</div>
122-
<div className="text-2xl font-bold">{analysis.paragraphs}</div>
124+
<div className="text-sm font-medium text-muted-foreground">Byte Size</div>
125+
<div className="text-2xl font-bold">{analysis.byteSize}</div>
123126
</div>
124127
</div>
125128

126-
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
127-
<div>
128-
<Label>Detailed Statistics</Label>
129-
<div className="p-3 bg-muted rounded-md font-mono text-sm mt-1">
130-
Characters (with spaces): {analysis.characters}<br/>
131-
Characters (without spaces): {analysis.charactersNoSpaces}<br/>
132-
Sentences: {analysis.sentences}<br/>
133-
Average words per sentence: {analysis.averageWordsPerSentence.toFixed(2)}<br/>
134-
Most frequent character: "{analysis.mostFrequentChar}"
135-
</div>
136-
</div>
137-
138-
<div>
139-
<Label>Character Frequency (Top 10)</Label>
140-
<div className="p-3 bg-muted rounded-md font-mono text-sm mt-1 max-h-32 overflow-y-auto">
141-
{Object.entries(analysis.charFrequency)
142-
.sort(([,a], [,b]) => (b as number) - (a as number))
143-
.slice(0, 10)
144-
.map(([char, count]) => (
145-
<div key={char}>
146-
"{char === ' ' ? 'space' : char === '\n' ? '\\n' : char}": {count as number}
147-
</div>
148-
))
149-
}
150-
</div>
129+
<div>
130+
<Label>Detailed Statistics</Label>
131+
<div className="p-3 bg-muted rounded-md font-mono text-sm mt-1">
132+
Characters (with spaces): {analysis.characters}<br/>
133+
Characters (without spaces): {analysis.charactersNoSpaces}<br/>
134+
Sentences: {analysis.sentences}<br/>
135+
Average words per sentence: {analysis.averageWordsPerSentence.toFixed(2)}<br/>
136+
Most frequent character: "{analysis.mostFrequentChar}"<br/>
137+
Byte size (UTF-8): {analysis.byteSize} bytes
151138
</div>
152139
</div>
153140
</>

client/src/lib/utils/advanced-converters.ts

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,24 @@ export function jsonToCsv(jsonString: string): string {
2626
if (!Array.isArray(data)) {
2727
throw new Error('JSON must be an array of objects');
2828
}
29-
29+
3030
if (data.length === 0) {
3131
return '';
3232
}
33-
33+
3434
const headers = Object.keys(data[0]);
3535
const csvRows = [headers.join(',')];
36-
36+
3737
for (const row of data) {
3838
const values = headers.map(header => {
3939
const value = row[header];
40-
return typeof value === 'string' && (value.includes(',') || value.includes('"'))
41-
? `"${value.replace(/"/g, '""')}"`
40+
return typeof value === 'string' && (value.includes(',') || value.includes('"'))
41+
? `"${value.replace(/"/g, '""')}"`
4242
: value;
4343
});
4444
csvRows.push(values.join(','));
4545
}
46-
46+
4747
return csvRows.join('\n');
4848
} catch (error) {
4949
throw new Error(`JSON to CSV conversion error: ${error instanceof Error ? error.message : 'Unknown error'}`);
@@ -56,21 +56,21 @@ export function csvToJson(csvString: string): string {
5656
if (lines.length < 2) {
5757
throw new Error('CSV must have at least a header row and one data row');
5858
}
59-
59+
6060
const headers = lines[0].split(',').map(h => h.trim());
6161
const result = [];
62-
62+
6363
for (let i = 1; i < lines.length; i++) {
6464
const values = lines[i].split(',').map(v => v.trim());
6565
const obj: any = {};
66-
66+
6767
headers.forEach((header, index) => {
6868
obj[header] = values[index] || '';
6969
});
70-
70+
7171
result.push(obj);
7272
}
73-
73+
7474
return JSON.stringify(result, null, 2);
7575
} catch (error) {
7676
throw new Error(`CSV to JSON conversion error: ${error instanceof Error ? error.message : 'Unknown error'}`);
@@ -98,25 +98,25 @@ export function rgbToHsl(r: number, g: number, b: number): { h: number; s: numbe
9898
r /= 255;
9999
g /= 255;
100100
b /= 255;
101-
101+
102102
const max = Math.max(r, g, b);
103103
const min = Math.min(r, g, b);
104104
let h = 0;
105105
let s = 0;
106106
const l = (max + min) / 2;
107-
107+
108108
if (max !== min) {
109109
const d = max - min;
110110
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
111-
111+
112112
switch (max) {
113113
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
114114
case g: h = (b - r) / d + 2; break;
115115
case b: h = (r - g) / d + 4; break;
116116
}
117117
h /= 6;
118118
}
119-
119+
120120
return {
121121
h: Math.round(h * 360),
122122
s: Math.round(s * 100),
@@ -128,7 +128,7 @@ export function hslToRgb(h: number, s: number, l: number): { r: number; g: numbe
128128
h /= 360;
129129
s /= 100;
130130
l /= 100;
131-
131+
132132
const hue2rgb = (p: number, q: number, t: number) => {
133133
if (t < 0) t += 1;
134134
if (t > 1) t -= 1;
@@ -137,9 +137,9 @@ export function hslToRgb(h: number, s: number, l: number): { r: number; g: numbe
137137
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
138138
return p;
139139
};
140-
140+
141141
let r, g, b;
142-
142+
143143
if (s === 0) {
144144
r = g = b = l;
145145
} else {
@@ -149,7 +149,7 @@ export function hslToRgb(h: number, s: number, l: number): { r: number; g: numbe
149149
g = hue2rgb(p, q, h);
150150
b = hue2rgb(p, q, h - 1/3);
151151
}
152-
152+
153153
return {
154154
r: Math.round(r * 255),
155155
g: Math.round(g * 255),
@@ -169,9 +169,9 @@ export function generateLoremIpsum(paragraphs: number, wordsPerParagraph: number
169169
'occaecat', 'cupidatat', 'non', 'proident', 'sunt', 'culpa', 'qui', 'officia',
170170
'deserunt', 'mollit', 'anim', 'id', 'est', 'laborum'
171171
];
172-
172+
173173
const result = [];
174-
174+
175175
for (let p = 0; p < paragraphs; p++) {
176176
const paragraph = [];
177177
for (let w = 0; w < wordsPerParagraph; w++) {
@@ -180,7 +180,7 @@ export function generateLoremIpsum(paragraphs: number, wordsPerParagraph: number
180180
}
181181
result.push(paragraph.join(' ') + '.');
182182
}
183-
183+
184184
return result.join('\n\n');
185185
}
186186

@@ -190,24 +190,26 @@ export function analyzeString(text: string) {
190190
const words = text.trim().split(/\s+/).filter(w => w.length > 0);
191191
const characters = text.length;
192192
const charactersNoSpaces = text.replace(/\s/g, '').length;
193-
const paragraphs = text.split(/\n\s*\n/).filter(p => p.trim().length > 0).length;
194-
193+
194+
// Calculate byte size (UTF-8 encoding)
195+
const byteSize = new TextEncoder().encode(text).length;
196+
195197
// Character frequency
196198
const charFreq: { [key: string]: number } = {};
197199
for (const char of text) {
198200
charFreq[char] = (charFreq[char] || 0) + 1;
199201
}
200-
202+
201203
return {
202204
characters,
203205
charactersNoSpaces,
204206
words: words.length,
205207
lines: lines.length,
206-
paragraphs,
207208
sentences: text.split(/[.!?]+/).filter(s => s.trim().length > 0).length,
208209
averageWordsPerSentence: words.length / text.split(/[.!?]+/).filter(s => s.trim().length > 0).length || 0,
209210
mostFrequentChar: Object.entries(charFreq).sort(([,a], [,b]) => b - a)[0]?.[0] || '',
210-
charFrequency: charFreq
211+
charFrequency: charFreq,
212+
byteSize
211213
};
212214
}
213215

@@ -252,13 +254,13 @@ export function htmlToJsx(html: string): string {
252254
// Cron expression parser
253255
export function parseCronExpression(expression: string): string {
254256
const parts = expression.trim().split(/\s+/);
255-
257+
256258
if (parts.length !== 5 && parts.length !== 6) {
257259
throw new Error('Invalid cron expression. Expected 5 or 6 parts.');
258260
}
259-
261+
260262
const [minute, hour, dayOfMonth, month, dayOfWeek, year] = parts;
261-
263+
262264
const parseField = (value: string, fieldName: string, min: number, max: number): string => {
263265
if (value === '*') return `any ${fieldName}`;
264266
if (value.includes('/')) {
@@ -274,19 +276,19 @@ export function parseCronExpression(expression: string): string {
274276
}
275277
return `${fieldName} ${value}`;
276278
};
277-
279+
278280
const minuteDesc = parseField(minute, 'minute', 0, 59);
279281
const hourDesc = parseField(hour, 'hour', 0, 23);
280282
const dayOfMonthDesc = parseField(dayOfMonth, 'day of month', 1, 31);
281283
const monthDesc = parseField(month, 'month', 1, 12);
282284
const dayOfWeekDesc = parseField(dayOfWeek, 'day of week', 0, 6);
283-
285+
284286
let description = `At ${minuteDesc} of ${hourDesc}, on ${dayOfMonthDesc} of ${monthDesc}, and on ${dayOfWeekDesc}`;
285-
287+
286288
if (year) {
287289
const yearDesc = parseField(year, 'year', 1970, 3000);
288290
description += `, in ${yearDesc}`;
289291
}
290-
292+
291293
return description;
292294
}

0 commit comments

Comments
 (0)