|
| 1 | +<!DOCTYPE html> |
| 2 | +<html lang="en"> |
| 3 | +<head> |
| 4 | + <meta charset="UTF-8"> |
| 5 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 6 | + <title>ReplaceText | Batch Text Replacement with Dictionaries</title> |
| 7 | + <meta name="description" content="Replace text in files based on dictionaries. Bidirectional replacement, configurable ignore patterns, Python CLI tool."> |
| 8 | + <link rel="preconnect" href="https://fonts.googleapis.com"> |
| 9 | + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
| 10 | + <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"> |
| 11 | + <style> |
| 12 | + *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } |
| 13 | + :root { |
| 14 | + --bg: #030014; |
| 15 | + --text: #ffffff; |
| 16 | + --accent-1: #0ea5e9; |
| 17 | + --accent-2: #6366f1; |
| 18 | + --accent-3: #8b5cf6; |
| 19 | + --card-bg: rgba(14, 165, 233, 0.08); |
| 20 | + --card-border: rgba(14, 165, 233, 0.2); |
| 21 | + } |
| 22 | + html { scroll-behavior: smooth; } |
| 23 | + body { |
| 24 | + font-family: 'Space Grotesk', -apple-system, sans-serif; |
| 25 | + background: var(--bg); |
| 26 | + color: var(--text); |
| 27 | + line-height: 1.6; |
| 28 | + overflow-x: hidden; |
| 29 | + } |
| 30 | + code, pre { font-family: 'JetBrains Mono', monospace; } |
| 31 | + .bg-gradient { |
| 32 | + position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; |
| 33 | + } |
| 34 | + .bg-gradient::before { |
| 35 | + content: ''; position: absolute; width: 150%; height: 150%; top: -25%; left: -25%; |
| 36 | + background: |
| 37 | + radial-gradient(ellipse at 20% 30%, rgba(14, 165, 233, 0.25) 0%, transparent 50%), |
| 38 | + radial-gradient(ellipse at 80% 50%, rgba(99, 102, 241, 0.2) 0%, transparent 50%), |
| 39 | + radial-gradient(ellipse at 40% 80%, rgba(139, 92, 246, 0.15) 0%, transparent 50%); |
| 40 | + animation: gradient-shift 20s ease-in-out infinite; |
| 41 | + } |
| 42 | + @keyframes gradient-shift { |
| 43 | + 0%, 100% { transform: translate(0, 0) rotate(0deg); } |
| 44 | + 50% { transform: translate(2%, 2%) rotate(1deg); } |
| 45 | + } |
| 46 | + .container { max-width: 900px; margin: 0 auto; padding: 0 24px; } |
| 47 | + |
| 48 | + /* Header */ |
| 49 | + .site-header { |
| 50 | + position: fixed; top: 0; left: 0; right: 0; z-index: 100; |
| 51 | + padding: 16px 24px; |
| 52 | + background: rgba(3, 0, 20, 0.8); |
| 53 | + backdrop-filter: blur(10px); |
| 54 | + border-bottom: 1px solid rgba(255,255,255,0.05); |
| 55 | + } |
| 56 | + .site-header .container { |
| 57 | + display: flex; justify-content: space-between; align-items: center; |
| 58 | + } |
| 59 | + .site-header a { text-decoration: none; color: inherit; } |
| 60 | + .site-header .brand { |
| 61 | + font-weight: 600; font-size: 1rem; color: rgba(255,255,255,0.9); |
| 62 | + transition: color 0.2s; |
| 63 | + } |
| 64 | + .site-header .brand:hover { color: var(--accent-1); } |
| 65 | + .site-header .nav-links { |
| 66 | + display: flex; align-items: center; gap: 24px; |
| 67 | + } |
| 68 | + .site-header .nav-link { |
| 69 | + color: rgba(255,255,255,0.7); font-size: 0.9rem; transition: color 0.2s; |
| 70 | + } |
| 71 | + .site-header .nav-link:hover { color: white; } |
| 72 | + .site-header .github-link { |
| 73 | + color: rgba(255,255,255,0.6); transition: color 0.2s; |
| 74 | + } |
| 75 | + .site-header .github-link:hover { color: white; } |
| 76 | + |
| 77 | + .hero { |
| 78 | + min-height: 70vh; display: flex; flex-direction: column; justify-content: center; |
| 79 | + padding: 120px 0 60px; text-align: center; |
| 80 | + } |
| 81 | + .logo { font-size: 4rem; margin-bottom: 16px; } |
| 82 | + .hero h1 { |
| 83 | + font-size: clamp(2.5rem, 6vw, 4rem); font-weight: 700; margin-bottom: 16px; |
| 84 | + background: linear-gradient(135deg, var(--accent-1), var(--accent-2)); |
| 85 | + -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; |
| 86 | + } |
| 87 | + .hero .tagline { |
| 88 | + font-size: 1.25rem; color: rgba(255,255,255,0.7); max-width: 600px; margin: 0 auto 32px; |
| 89 | + } |
| 90 | + .badges { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-bottom: 32px; } |
| 91 | + .badge { |
| 92 | + padding: 8px 16px; background: var(--card-bg); border: 1px solid var(--card-border); |
| 93 | + border-radius: 999px; font-size: 0.85rem; color: var(--accent-1); |
| 94 | + } |
| 95 | + .badge-highlight { |
| 96 | + background: rgba(139, 92, 246, 0.15); border-color: rgba(139, 92, 246, 0.3); |
| 97 | + color: #a78bfa; |
| 98 | + } |
| 99 | + .buttons { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; } |
| 100 | + .btn { |
| 101 | + display: inline-flex; align-items: center; gap: 8px; padding: 14px 28px; |
| 102 | + border-radius: 12px; font-size: 1rem; font-weight: 600; text-decoration: none; |
| 103 | + transition: all 0.3s ease; |
| 104 | + } |
| 105 | + .btn-primary { |
| 106 | + background: linear-gradient(135deg, var(--accent-1), var(--accent-2)); color: white; |
| 107 | + } |
| 108 | + .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 20px 40px rgba(14, 165, 233, 0.3); } |
| 109 | + .btn-secondary { |
| 110 | + background: var(--card-bg); color: white; border: 1px solid var(--card-border); |
| 111 | + } |
| 112 | + .btn-secondary:hover { border-color: var(--accent-1); } |
| 113 | + .btn svg { width: 20px; height: 20px; } |
| 114 | + |
| 115 | + .install { |
| 116 | + background: var(--card-bg); border: 1px solid var(--card-border); border-radius: 16px; |
| 117 | + padding: 20px 24px; margin-bottom: 60px; display: flex; align-items: center; |
| 118 | + justify-content: space-between; gap: 16px; flex-wrap: wrap; |
| 119 | + } |
| 120 | + .install code { font-size: 1.1rem; color: var(--accent-1); } |
| 121 | + .install button { |
| 122 | + background: rgba(255,255,255,0.1); border: none; padding: 8px 16px; |
| 123 | + border-radius: 8px; color: white; cursor: pointer; font-size: 0.9rem; |
| 124 | + } |
| 125 | + .install button:hover { background: rgba(255,255,255,0.2); } |
| 126 | + |
| 127 | + .features { padding: 60px 0; } |
| 128 | + .section-title { font-size: 2rem; font-weight: 700; text-align: center; margin-bottom: 48px; } |
| 129 | + .feature-grid { |
| 130 | + display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 24px; |
| 131 | + } |
| 132 | + .feature { |
| 133 | + background: var(--card-bg); border: 1px solid var(--card-border); border-radius: 16px; |
| 134 | + padding: 24px; transition: all 0.3s ease; |
| 135 | + } |
| 136 | + .feature:hover { border-color: var(--accent-1); transform: translateY(-4px); } |
| 137 | + .feature-icon { font-size: 2rem; margin-bottom: 12px; } |
| 138 | + .feature h3 { font-size: 1.1rem; margin-bottom: 8px; } |
| 139 | + .feature p { font-size: 0.9rem; color: rgba(255,255,255,0.7); } |
| 140 | + |
| 141 | + .code-section { padding: 60px 0; } |
| 142 | + .code-block { |
| 143 | + background: #0d1117; border: 1px solid #30363d; border-radius: 12px; overflow: hidden; |
| 144 | + margin-bottom: 24px; |
| 145 | + } |
| 146 | + .code-header { |
| 147 | + background: #161b22; padding: 12px 16px; border-bottom: 1px solid #30363d; |
| 148 | + font-size: 0.85rem; color: rgba(255,255,255,0.6); |
| 149 | + } |
| 150 | + .code-block pre { padding: 20px; overflow-x: auto; font-size: 0.9rem; line-height: 1.6; } |
| 151 | + .code-block code { color: #e6edf3; } |
| 152 | + .comment { color: #8b949e; } |
| 153 | + .keyword { color: #ff7b72; } |
| 154 | + .string { color: #a5d6ff; } |
| 155 | + .key { color: #7ee787; } |
| 156 | + |
| 157 | + footer { |
| 158 | + padding: 40px 0; text-align: center; border-top: 1px solid var(--card-border); margin-top: 60px; |
| 159 | + } |
| 160 | + footer p { color: rgba(255,255,255,0.5); font-size: 0.9rem; } |
| 161 | + footer a { color: var(--accent-1); text-decoration: none; } |
| 162 | + footer a:hover { text-decoration: underline; } |
| 163 | + |
| 164 | + @media (max-width: 600px) { |
| 165 | + .hero { padding: 80px 0 40px; min-height: auto; } |
| 166 | + .install { flex-direction: column; text-align: center; } |
| 167 | + } |
| 168 | + </style> |
| 169 | +</head> |
| 170 | +<body> |
| 171 | + <div class="bg-gradient"></div> |
| 172 | + |
| 173 | + <header class="site-header"> |
| 174 | + <div class="container"> |
| 175 | + <a href="https://cainky.github.io/" class="brand">Kyle Cain</a> |
| 176 | + <nav class="nav-links"> |
| 177 | + <a href="https://cainky.github.io/#projects" class="nav-link">Projects</a> |
| 178 | + <a href="https://github.com/cainky" target="_blank" rel="noopener" class="github-link"> |
| 179 | + <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg> |
| 180 | + </a> |
| 181 | + </nav> |
| 182 | + </div> |
| 183 | + </header> |
| 184 | + |
| 185 | + <section class="hero"> |
| 186 | + <div class="container"> |
| 187 | + <div class="logo">🔄</div> |
| 188 | + <h1>ReplaceText</h1> |
| 189 | + <p class="tagline">Batch text replacement powered by dictionaries. Replace keys with values or values with keys across entire directories.</p> |
| 190 | + <div class="badges"> |
| 191 | + <span class="badge">Python 3.8+</span> |
| 192 | + <span class="badge">Poetry</span> |
| 193 | + <span class="badge badge-highlight">Bidirectional</span> |
| 194 | + <span class="badge">GPL-3.0</span> |
| 195 | + </div> |
| 196 | + <div class="buttons"> |
| 197 | + <a href="https://github.com/cainky/ReplaceText" target="_blank" class="btn btn-primary"> |
| 198 | + <svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg> |
| 199 | + View on GitHub |
| 200 | + </a> |
| 201 | + <a href="https://github.com/cainky/ReplaceText#usage" target="_blank" class="btn btn-secondary"> |
| 202 | + Documentation |
| 203 | + </a> |
| 204 | + </div> |
| 205 | + </div> |
| 206 | + </section> |
| 207 | + |
| 208 | + <div class="container"> |
| 209 | + <div class="install"> |
| 210 | + <code>git clone https://github.com/cainky/ReplaceText.git && cd ReplaceText && poetry install</code> |
| 211 | + <button onclick="navigator.clipboard.writeText('git clone https://github.com/cainky/ReplaceText.git && cd ReplaceText && poetry install')">Copy</button> |
| 212 | + </div> |
| 213 | + </div> |
| 214 | + |
| 215 | + <section class="features"> |
| 216 | + <div class="container"> |
| 217 | + <h2 class="section-title">Features</h2> |
| 218 | + <div class="feature-grid"> |
| 219 | + <div class="feature"> |
| 220 | + <div class="feature-icon">🔁</div> |
| 221 | + <h3>Bidirectional Replacement</h3> |
| 222 | + <p>Replace keys with values or values with keys. Perfect for encoding/decoding or reversible transformations.</p> |
| 223 | + </div> |
| 224 | + <div class="feature"> |
| 225 | + <div class="feature-icon">📚</div> |
| 226 | + <h3>Multiple Dictionaries</h3> |
| 227 | + <p>Define multiple replacement dictionaries in one config file and switch between them easily.</p> |
| 228 | + </div> |
| 229 | + <div class="feature"> |
| 230 | + <div class="feature-icon">🚫</div> |
| 231 | + <h3>Smart Ignore Patterns</h3> |
| 232 | + <p>Skip files by extension, prefix, or entire directories. Never accidentally modify binaries or dependencies.</p> |
| 233 | + </div> |
| 234 | + <div class="feature"> |
| 235 | + <div class="feature-icon">📁</div> |
| 236 | + <h3>Batch Processing</h3> |
| 237 | + <p>Process entire directories at once. Recursively replace text across all matching files.</p> |
| 238 | + </div> |
| 239 | + <div class="feature"> |
| 240 | + <div class="feature-icon">⚙️</div> |
| 241 | + <h3>JSON Configuration</h3> |
| 242 | + <p>Simple JSON config file for dictionaries and ignore patterns. Easy to version control.</p> |
| 243 | + </div> |
| 244 | + <div class="feature"> |
| 245 | + <div class="feature-icon">🎯</div> |
| 246 | + <h3>Auto-Select Dictionary</h3> |
| 247 | + <p>If only one dictionary exists, it's automatically selected. No extra prompts needed.</p> |
| 248 | + </div> |
| 249 | + </div> |
| 250 | + </div> |
| 251 | + </section> |
| 252 | + |
| 253 | + <section class="code-section"> |
| 254 | + <div class="container"> |
| 255 | + <h2 class="section-title">Quick Start</h2> |
| 256 | + <div class="code-block"> |
| 257 | + <div class="code-header">config.json</div> |
| 258 | + <pre><code>{ |
| 259 | + <span class="key">"dictionaries"</span>: { |
| 260 | + <span class="key">"obfuscate"</span>: { |
| 261 | + <span class="string">"password"</span>: <span class="string">"p4ssw0rd"</span>, |
| 262 | + <span class="string">"admin"</span>: <span class="string">"4dm1n"</span>, |
| 263 | + <span class="string">"secret"</span>: <span class="string">"s3cr3t"</span> |
| 264 | + } |
| 265 | + }, |
| 266 | + <span class="key">"ignore_extensions"</span>: [<span class="string">".exe"</span>, <span class="string">".dll"</span>, <span class="string">".bin"</span>], |
| 267 | + <span class="key">"ignore_directories"</span>: [<span class="string">"node_modules"</span>, <span class="string">"venv"</span>, <span class="string">".git"</span>], |
| 268 | + <span class="key">"ignore_file_prefixes"</span>: [<span class="string">"."</span>, <span class="string">"_"</span>] |
| 269 | +}</code></pre> |
| 270 | + </div> |
| 271 | + <div class="code-block"> |
| 272 | + <div class="code-header">Terminal</div> |
| 273 | + <pre><code><span class="comment"># Run the replacement tool</span> |
| 274 | +$ poetry run python replace_text/replace_text.py |
| 275 | + |
| 276 | +<span class="comment"># Select direction:</span> |
| 277 | +<span class="string">Enter '1' for keys-to-values</span> |
| 278 | +<span class="string">Enter '2' for values-to-keys</span> |
| 279 | + |
| 280 | +<span class="comment"># Enter folder path and dictionary name</span> |
| 281 | +<span class="comment"># All matching files will be processed!</span></code></pre> |
| 282 | + </div> |
| 283 | + </div> |
| 284 | + </section> |
| 285 | + |
| 286 | + <footer> |
| 287 | + <div class="container"> |
| 288 | + <p>Built by <a href="https://cainky.github.io/">Kyle Cain</a> · <a href="https://github.com/cainky/ReplaceText">GitHub</a></p> |
| 289 | + </div> |
| 290 | + </footer> |
| 291 | +</body> |
| 292 | +</html> |
0 commit comments