Enhance mobile experience and add zalgo text variants

Mobile improvements:
- Comprehensive responsive design for 320px-4K screens
- Touch-optimized controls with larger touch targets
- iOS zoom prevention with 16px font sizes on inputs
- Swipe-friendly interface with better spacing
- Portrait and landscape orientation support
- Enhanced accessibility with better contrast and sizes

Zalgo variants implemented:
- Full Chaos: Balanced corruption (default)
- Above Only: Marks above characters only
- Below Only: Marks below characters only
- Middle Only: Overlaying marks
- Mini Glitch: Subtle corruption
- Heavy Corruption: Maximum chaos overload

UI enhancements:
- Added corruption mode selector dropdown
- Reorganized controls into responsive groups
- Improved mobile control layouts
- Better visual hierarchy and spacing

Code quality:
- Fixed ESLint/Prettier indentation conflict
- Enhanced ZalgoGenerator with mode parameter
- Added event handlers for mode selection
- Comprehensive mobile CSS with multiple breakpoints

Documentation:
- Created comprehensive README with zalgo examples
- Documented all corruption modes with examples
- Added development and deployment instructions

The app now provides a perfect mobile experience with
diverse zalgo corruption options for creative text effects.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2025-08-18 20:30:05 +02:00
commit 7b0a3746d5
6 changed files with 377 additions and 23 deletions

View file

@ -13,6 +13,7 @@ const inputText = document.getElementById('inputText');
const outputText = document.getElementById('outputText');
const intensitySlider = document.getElementById('intensity');
const intensityValue = document.getElementById('intensityValue');
const zalgoModeSelect = document.getElementById('zalgoMode');
const clearBtn = document.getElementById('clearBtn');
const copyNotification = document.getElementById('copyNotification');
@ -22,9 +23,10 @@ const copyNotification = document.getElementById('copyNotification');
function updateOutput() {
const text = inputText.value;
const intensity = parseInt(intensitySlider.value);
const mode = zalgoModeSelect.value;
if (text) {
outputText.value = zalgo.generate(text, intensity);
outputText.value = zalgo.generate(text, intensity, mode);
} else {
outputText.value = '';
}
@ -74,6 +76,8 @@ intensitySlider.addEventListener('input', () => {
updateOutput();
});
zalgoModeSelect.addEventListener('change', updateOutput);
outputText.addEventListener('click', copyToClipboard);
clearBtn.addEventListener('click', clearAll);

View file

@ -24,9 +24,23 @@
<main>
<div class="controls">
<label for="intensity">Corruption Intensity:</label>
<input type="range" id="intensity" min="1" max="10" value="5" />
<span id="intensityValue">5</span>
<div class="control-group">
<label for="zalgoMode">Corruption Mode:</label>
<select id="zalgoMode">
<option value="full">Full Chaos</option>
<option value="above">Above Only</option>
<option value="below">Below Only</option>
<option value="middle">Middle Only</option>
<option value="mini">Mini Glitch</option>
<option value="heavy">Heavy Corruption</option>
</select>
</div>
<div class="control-group">
<label for="intensity">Intensity:</label>
<input type="range" id="intensity" min="1" max="10" value="5" />
<span id="intensityValue">5</span>
</div>
</div>
<div class="text-area-container">

View file

@ -96,8 +96,8 @@ h1 {
.controls {
display: flex;
align-items: center;
gap: 15px;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 30px;
padding: 20px;
background: var(--bg-tertiary);
@ -105,9 +105,42 @@ h1 {
border: 1px solid var(--border);
}
.control-group {
display: flex;
align-items: center;
gap: 10px;
flex: 1;
min-width: 200px;
}
.controls label {
color: var(--text-secondary);
font-size: 0.95rem;
white-space: nowrap;
min-width: 80px;
}
#zalgoMode {
flex: 1;
padding: 8px 12px;
background: var(--bg-primary);
border: 2px solid var(--border);
border-radius: 8px;
color: var(--text-primary);
font-size: 0.95rem;
outline: none;
transition: all 0.3s ease;
min-width: 120px;
}
#zalgoMode:focus {
border-color: var(--accent);
box-shadow: 0 0 10px var(--shadow);
}
#zalgoMode option {
background: var(--bg-primary);
color: var(--text-primary);
}
#intensity {
@ -277,24 +310,126 @@ footer p {
}
/* Mobile responsiveness */
@media (max-width: 600px) {
@media (max-width: 768px) {
body {
padding: 10px;
}
.container {
padding: 25px;
padding: 20px;
max-width: 100%;
}
h1 {
font-size: 2rem;
}
.subtitle {
font-size: 1rem;
}
.controls {
flex-direction: column;
gap: 15px;
padding: 15px;
}
.control-group {
flex-direction: column;
align-items: stretch;
gap: 10px;
gap: 8px;
min-width: auto;
}
.controls label {
min-width: auto;
font-size: 0.9rem;
}
#zalgoMode {
width: 100%;
padding: 12px;
font-size: 1rem;
min-width: auto;
}
#intensity {
width: 100%;
height: 8px;
}
#intensity::-webkit-slider-thumb {
width: 24px;
height: 24px;
}
#intensity::-moz-range-thumb {
width: 24px;
height: 24px;
}
textarea {
min-height: 140px;
font-size: 1rem;
padding: 15px;
}
.clear-btn {
padding: 18px;
font-size: 1.1rem;
}
.copy-notification {
padding: 15px 25px;
font-size: 1rem;
}
}
/* Small mobile devices */
@media (max-width: 480px) {
.container {
padding: 15px;
}
h1 {
font-size: 1.8rem;
}
.controls {
padding: 12px;
gap: 12px;
}
textarea {
min-height: 120px;
font-size: 0.95rem;
font-size: 16px; /* Prevents zoom on iOS */
}
#zalgoMode {
font-size: 16px; /* Prevents zoom on iOS */
}
}
/* Touch-friendly improvements */
@media (hover: none) and (pointer: coarse) {
/* Touch device specific styles */
textarea {
font-size: 16px; /* Prevents zoom on mobile browsers */
}
#zalgoMode {
font-size: 16px;
padding: 15px;
}
.clear-btn {
min-height: 48px; /* Minimum touch target size */
}
#outputText {
cursor: pointer;
-webkit-user-select: all;
user-select: all;
}
}

View file

@ -215,12 +215,13 @@ class ZalgoGenerator {
}
/**
* Generate zalgo text with specified intensity
* Generate zalgo text with specified intensity and mode
* @param {string} text - The input text to corrupt
* @param {number} intensity - Corruption intensity (1-10)
* @param {string} mode - Corruption mode (full, above, below, middle, mini, heavy)
* @returns {string} - The corrupted zalgo text
*/
generate(text, intensity = 5) {
generate(text, intensity = 5, mode = 'full') {
if (!text) return '';
// Normalize intensity to 1-10 range
@ -236,20 +237,52 @@ class ZalgoGenerator {
continue;
}
// Calculate how many combining characters to add based on intensity
// Higher intensity = more corruption
// Calculate how many combining characters to add based on intensity and mode
const factor = intensity / 10;
// Add characters above (0-3 based on intensity)
const aboveCount = Math.floor(Math.random() * (4 * factor));
let aboveCount = 0;
let middleCount = 0;
let belowCount = 0;
switch (mode) {
case 'above':
aboveCount = Math.floor(Math.random() * (6 * factor));
break;
case 'below':
belowCount = Math.floor(Math.random() * (6 * factor));
break;
case 'middle':
middleCount = Math.floor(Math.random() * (4 * factor));
break;
case 'mini':
// Light corruption - fewer characters
aboveCount = Math.floor(Math.random() * (2 * factor));
middleCount = Math.floor(Math.random() * (1 * factor));
belowCount = Math.floor(Math.random() * (2 * factor));
break;
case 'heavy':
// Heavy corruption - more characters
aboveCount = Math.floor(Math.random() * (8 * factor)) + 1;
middleCount = Math.floor(Math.random() * (5 * factor)) + 1;
belowCount = Math.floor(Math.random() * (8 * factor)) + 1;
break;
case 'full':
default:
// Balanced corruption
aboveCount = Math.floor(Math.random() * (4 * factor));
middleCount = Math.floor(Math.random() * (3 * factor));
belowCount = Math.floor(Math.random() * (4 * factor));
break;
}
// Add the calculated characters
result += this.randomChars(this.above, aboveCount);
// Add characters in middle (0-2 based on intensity)
const middleCount = Math.floor(Math.random() * (3 * factor));
result += this.randomChars(this.middle, middleCount);
// Add characters below (0-3 based on intensity)
const belowCount = Math.floor(Math.random() * (4 * factor));
result += this.randomChars(this.below, belowCount);
}