diff --git a/src/constants/tools.ts b/src/constants/tools.ts
index 2ab64fe..c398f64 100644
--- a/src/constants/tools.ts
+++ b/src/constants/tools.ts
@@ -256,6 +256,15 @@ export const TOOLS: Tool[] = [
template: '',
icon: 'floppy-disk',
tags: ['data', 'unit', 'convertor', 'bytes', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb', 'bit', 'information'],
+ },
+ {
+ id: 'character-counter',
+ label: 'Character Counter',
+ version: '1.0.0',
+ category: ToolCategory.Util,
+ template: '',
+ icon: 'rectangle-ellipsis',
+ tags: ['character', 'counter', 'length'],
},
{
id: 'unix-path-convertor',
diff --git a/src/tools/components/character-counter/CharacterCounter.ts b/src/tools/components/character-counter/CharacterCounter.ts
new file mode 100644
index 0000000..a6c82e4
--- /dev/null
+++ b/src/tools/components/character-counter/CharacterCounter.ts
@@ -0,0 +1,122 @@
+import { html, css } from 'lit';
+import { customElement, state } from 'lit/decorators.js';
+import { BaseTool } from '../../base/BaseTool';
+
+@customElement('character-counter')
+export class CharacterCounter extends BaseTool {
+ @state() private input = 'This a text message';
+ @state() private count: number = 0;
+ @state() private alert: { type: 'error' | 'warning'; message: string } | null = null;
+
+ private styles = css`
+ ${BaseTool.styles}
+ `;
+
+ constructor() {
+ super();
+ this.updateCount();
+ }
+
+ protected renderTool() {
+ return html`
+
+
+ `;
+ }
+
+ private renderConversionRow(counted: number) {
+ return html`
+
+ `;
+ }
+
+ private handleInput(e: InputEvent) {
+ const input = e.target as HTMLInputElement;
+ this.input = input.value;
+
+ if (this.input && !/^[0-9]*\.?[0-9]*$/.test(this.input)) {
+ this.alert = {
+ type: 'error',
+ message: 'Please enter a valid number'
+ };
+ return;
+ } else {
+ this.alert = null;
+ }
+
+ this.updateCount();
+ }
+
+ private clearAll() {
+ this.input = '';
+ this.alert = null;
+ this.updateCount();
+ }
+
+ private updateCount() {
+ if (!this.input || isNaN(Number(this.input))) {
+ this.count = 0;
+ return;
+ }
+
+ this.count = this.countChars(this.input);
+ }
+
+ private countChars(input:string): number {
+ const counted: number = input.length;
+ return counted;
+ }
+}
\ No newline at end of file
diff --git a/src/tools/toolComponents.ts b/src/tools/toolComponents.ts
index 667da06..def19e4 100644
--- a/src/tools/toolComponents.ts
+++ b/src/tools/toolComponents.ts
@@ -23,6 +23,7 @@ import './components/cubic-bezier/CubicBezier';
import './components/data-format-convertor/DataFormatConvertor';
import './components/datetime-convertor/DatetimeConvertor';
import './components/data-unit-convertor/DataUnitConvertor';
+import './components/character-counter/CharacterCounter';
import './components/diff-checker/DiffChecker';
import './components/escape-html-entities/EscapeHtmlEntities';
import './components/gradient-maker/GradientMaker';
diff --git a/website/src/components/landing/tool-showcase.tsx b/website/src/components/landing/tool-showcase.tsx
index bf518c2..1757f69 100644
--- a/website/src/components/landing/tool-showcase.tsx
+++ b/website/src/components/landing/tool-showcase.tsx
@@ -74,6 +74,7 @@ const TOOLS: Tool[] = [
{ name: 'QR Code', category: 'utility', icon: QrCode },
{ name: 'HTTP Status', category: 'utility', icon: Server },
{ name: 'Data Unit', category: 'utility', icon: Save },
+ { name: 'Char Count', category: 'utility', icon: RectangleEllipsis },
{ name: 'Path Convertor', category: 'utility', icon: FolderPen },
{ name: 'Number Base', category: 'utility', icon: Binary },
{ name: 'Token Generator', category: 'crypto', icon: Tag },