CoolFace
Apppublic

syscycle/svg-text-to-path

sourceHugging Faceupdated 2mo agoView on Hugging Face
0likes
index.html807 linesDownload Raw Back to root
1<!DOCTYPE html>2<html lang="tr" class="h-full bg-slate-900 text-slate-100">3<head>4    <meta charset="UTF-8">5    <meta name="viewport" content="width=device-width, initial-scale=1.0">6    <title>Android Text-to-SVG Path Generator</title>7    <script src="https://cdn.tailwindcss.com"></script>8    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">9    <script src="https://cdnjs.cloudflare.com/ajax/libs/opentype.js/1.3.4/opentype.min.js"></script>10    11    <style>12        ::-webkit-scrollbar {13            width: 6px;14            height: 6px;15        }16        ::-webkit-scrollbar-track {17            background: #0f172a;18        }19        ::-webkit-scrollbar-thumb {20            background: #334155;21            border-radius: 3px;22        }23        ::-webkit-scrollbar-thumb:hover {24            background: #475569;25        }26    </style>27</head>28<body class="h-full flex flex-col font-sans antialiased overflow-x-hidden">29 30    <header class="border-b border-slate-800 bg-slate-950/90 backdrop-blur-md sticky top-0 z-50 px-4 py-3">31        <div class="max-w-7xl mx-auto flex items-center justify-between">32            <div class="flex items-center space-x-3">33                <div class="w-10 h-10 rounded-xl bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-emerald-400">34                    <i class="fa-brands fa-android text-2xl"></i>35                </div>36                <div>37                    <h1 class="text-lg font-bold text-slate-100 flex items-center gap-2">38                        Android Text-to-Path SVG39                        <span class="text-xs font-semibold px-2 py-0.5 rounded-full bg-emerald-500/20 text-emerald-300 border border-emerald-500/30">40                            Real &lt;path d="..."&gt; Outlines41                        </span>42                    </h1>43                    <p class="text-xs text-slate-400">Android fontlarıyla saf vektör yoluna (vector curve) dönüştürme motoru</p>44                </div>45            </div>46            47            <div class="flex items-center gap-2">48                <button id="btn-export-svg" class="px-4 py-2 bg-emerald-600 hover:bg-emerald-500 text-white text-sm font-medium rounded-lg shadow-lg shadow-emerald-900/30 transition flex items-center gap-2">49                    <i class="fa-solid fa-download"></i>50                    <span>SVG Path İndir</span>51                </button>52                <button id="btn-copy-code" class="px-4 py-2 bg-slate-800 hover:bg-slate-700 text-slate-200 text-sm font-medium rounded-lg border border-slate-700 transition flex items-center gap-2">53                    <i class="fa-regular fa-copy"></i>54                    <span>Kodu Kopyala</span>55                </button>56            </div>57        </div>58    </header>59 60    <main class="flex-1 max-w-7xl w-full mx-auto p-4 md:p-6 grid grid-cols-1 lg:grid-cols-12 gap-6 overflow-hidden">61        <div class="lg:col-span-5 flex flex-col gap-5 overflow-y-auto pr-1 max-h-[calc(100vh-100px)]">62            <div class="p-3.5 bg-emerald-950/40 border border-emerald-500/30 rounded-xl text-xs text-emerald-200 flex items-start gap-3">63                <i class="fa-solid fa-bezier-curve text-emerald-400 text-base shrink-0 mt-0.5"></i>64                <div>65                    <strong>Gerçek Vektör Dönüştürücü:</strong> Metniniz matematiksel çizgi ve eğri komutlarına (<code>&lt;path d="M..." /&gt;</code>) dönüştürülür. Hedef cihazda font kurulu olmasına gerek kalmaz; Illustrator/Figma'da açılabilir ve düzenlenebilir.66                </div>67            </div>68            <div class="bg-slate-800/40 border border-slate-700/80 rounded-xl p-4 space-y-3">69                <label class="block text-xs font-semibold text-slate-300 uppercase tracking-wider flex justify-between">70                    <span>Metin İçeriği</span>71                    <span class="text-slate-500 font-normal">Çoklu satır desteklenir</span>72                </label>73                <textarea id="input-text" rows="3" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-3 text-sm text-slate-100 placeholder-slate-500 focus:outline-none focus:border-emerald-500 focus:ring-1 focus:ring-emerald-500 transition resize-y" placeholder="Vektör path yapmak istediğiniz metni girin...">Android OS74System Vector</textarea>75            </div>76            <div class="bg-slate-800/40 border border-slate-700/80 rounded-xl p-4 space-y-4">77                <h3 class="text-xs font-semibold text-slate-300 uppercase tracking-wider border-b border-slate-700/60 pb-2 flex items-center justify-between">78                    <span>Android Font Seçimi</span>79                    <i class="fa-solid fa-font text-slate-500"></i>80                </h3>81                <div class="space-y-1">82                    <label class="text-xs text-slate-400">Android Sistem Fontu (TTF)</label>83                    <select id="select-font-preset" class="w-full bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-xs text-slate-200 focus:outline-none focus:border-emerald-500">84                        <option value="roboto-regular">Roboto Regular (Android Standart)</option>85                        <option value="roboto-bold">Roboto Bold (Android Kalın)</option>86                        <option value="roboto-light">Roboto Light (Android İnce)</option>87                        <option value="roboto-italic">Roboto Italic (Android Eğik)</option>88                        <option value="noto-sans">Noto Sans (Android Global / Türkçe)</option>89                        <option value="roboto-mono">Roboto Mono (Android Monospace)</option>90                        <option value="custom">Özel Font Yükle (.ttf / .otf)</option>91                    </select>92                </div>93 94                <!-- Custom Font Upload (Hidden by default) -->95                <div id="section-custom-font" class="hidden space-y-2 p-3 bg-slate-900/60 rounded-lg border border-slate-700/50">96                    <label class="block text-xs text-slate-300 font-medium">Font Dosyası Yükleyin (.ttf veya .otf)</label>97                    <input id="file-custom-font" type="file" accept=".ttf,.otf,.woff" class="block w-full text-xs text-slate-400 file:mr-3 file:py-1.5 file:px-3 file:rounded-lg file:border-0 file:text-xs file:font-medium file:bg-emerald-600 file:text-white hover:file:bg-emerald-500 cursor-pointer">98                </div>99                <div id="font-loading-status" class="flex items-center gap-2 text-xs text-emerald-400 font-mono">100                    <i class="fa-solid fa-spinner fa-spin text-slate-400"></i>101                    <span>Font yükleniyor...</span>102                </div>103            </div>104            <div class="bg-slate-800/40 border border-slate-700/80 rounded-xl p-4 space-y-4">105                <h3 class="text-xs font-semibold text-slate-300 uppercase tracking-wider border-b border-slate-700/60 pb-2 flex items-center justify-between">106                    <span>Boyut & Düzen</span>107                    <i class="fa-solid fa-sliders text-slate-500"></i>108                </h3>109                <div>110                    <div class="flex justify-between text-xs text-slate-400 mb-1">111                        <span>Font Boyutu (px)</span>112                        <span id="val-font-size" class="text-emerald-400 font-mono">56</span>113                    </div>114                    <input id="slider-font-size" type="range" min="16" max="200" value="56" class="w-full accent-emerald-500 bg-slate-700 h-1.5 rounded-lg appearance-none cursor-pointer">115                </div>116                <div>117                    <div class="flex justify-between text-xs text-slate-400 mb-1">118                        <span>Satır Yüksekliği Çarpanı</span>119                        <span id="val-line-height" class="text-emerald-400 font-mono">1.2</span>120                    </div>121                    <input id="slider-line-height" type="range" min="0.8" max="2.5" step="0.1" value="1.2" class="w-full accent-emerald-500 bg-slate-700 h-1.5 rounded-lg appearance-none cursor-pointer">122                </div>123                <div>124                    <div class="flex justify-between text-xs text-slate-400 mb-1">125                        <span>Harf Aralığı (px)</span>126                        <span id="val-letter-spacing" class="text-emerald-400 font-mono">0</span>127                    </div>128                    <input id="slider-letter-spacing" type="range" min="-10" max="40" value="0" class="w-full accent-emerald-500 bg-slate-700 h-1.5 rounded-lg appearance-none cursor-pointer">129                </div>130                <div>131                    <label class="text-xs text-slate-400 block mb-1">Path Hizalama</label>132                    <div class="grid grid-cols-3 gap-2">133                        <button type="button" data-align="left" class="btn-align py-1.5 bg-slate-800 text-slate-300 hover:bg-slate-700 rounded border border-slate-700 text-xs font-medium flex items-center justify-center gap-1">134                            <i class="fa-solid fa-align-left"></i> Sol135                        </button>136                        <button type="button" data-align="center" class="btn-align py-1.5 bg-emerald-600 text-white rounded border border-emerald-500 text-xs font-medium flex items-center justify-center gap-1">137                            <i class="fa-solid fa-align-center"></i> Orta138                        </button>139                        <button type="button" data-align="end" class="btn-align py-1.5 bg-slate-800 text-slate-300 hover:bg-slate-700 rounded border border-slate-700 text-xs font-medium flex items-center justify-center gap-1">140                            <i class="fa-solid fa-align-right"></i> Sağ141                        </button>142                    </div>143                </div>144            </div>145 146            <!-- Colors & Path Effects -->147            <div class="bg-slate-800/40 border border-slate-700/80 rounded-xl p-4 space-y-4">148                <h3 class="text-xs font-semibold text-slate-300 uppercase tracking-wider border-b border-slate-700/60 pb-2 flex items-center justify-between">149                    <span>Path Renk & Stil</span>150                    <i class="fa-solid fa-palette text-slate-500"></i>151                </h3>152                <div class="grid grid-cols-2 gap-2">153                    <button id="tab-fill-solid" class="py-1.5 text-xs rounded-lg bg-emerald-600 text-white border border-emerald-500 font-medium">Düz Dolgu</button>154                    <button id="tab-fill-gradient" class="py-1.5 text-xs rounded-lg bg-slate-800 text-slate-300 hover:bg-slate-700 border border-slate-700 font-medium">Gradyan Dolgu</button>155                </div>156                <div id="section-fill-solid" class="flex items-center justify-between">157                    <span class="text-xs text-slate-400">Path Dolgu Rengi</span>158                    <div class="flex items-center gap-2">159                        <input id="color-text" type="color" value="#38bdf8" class="w-8 h-8 rounded bg-transparent cursor-pointer border-0">160                        <input id="hex-text" type="text" value="#38bdf8" class="w-20 bg-slate-900 border border-slate-700 rounded text-xs px-2 py-1 text-slate-200 font-mono uppercase">161                    </div>162                </div>163                <div id="section-fill-gradient" class="hidden space-y-3">164                    <div class="flex items-center justify-between">165                        <span class="text-xs text-slate-400">Başlangıç Renk</span>166                        <input id="color-grad-1" type="color" value="#38bdf8" class="w-8 h-8 rounded bg-transparent cursor-pointer border-0">167                    </div>168                    <div class="flex items-center justify-between">169                        <span class="text-xs text-slate-400">Bitiş Renk</span>170                        <input id="color-grad-2" type="color" value="#34d399" class="w-8 h-8 rounded bg-transparent cursor-pointer border-0">171                    </div>172                    <div class="flex items-center justify-between">173                        <span class="text-xs text-slate-400">Açı</span>174                        <select id="select-grad-angle" class="bg-slate-900 border border-slate-700 rounded text-xs px-2 py-1 text-slate-200">175                            <option value="horizontal">Yatay (0°)</option>176                            <option value="vertical">Dikey (90°)</option>177                            <option value="diagonal">Diyagonal (45°)</option>178                        </select>179                    </div>180                </div>181                <div class="border-t border-slate-700/60 pt-3 space-y-2">182                    <div class="flex items-center justify-between">183                        <label class="text-xs text-slate-400 flex items-center gap-2">184                            <input id="chk-stroke" type="checkbox" class="rounded accent-emerald-500">185                            <span>Vektör Dış Çizgisi (Stroke)</span>186                        </label>187                        <input id="color-stroke" type="color" value="#0f172a" class="w-7 h-7 rounded bg-transparent cursor-pointer border-0">188                    </div>189                    <div id="section-stroke-width" class="hidden flex items-center justify-between gap-3 pt-1">190                        <span class="text-xs text-slate-500">Çizgi Kalınlığı (px)</span>191                        <input id="slider-stroke-width" type="range" min="1" max="15" value="2" class="w-32 accent-emerald-500 bg-slate-700 h-1.5 rounded-lg appearance-none cursor-pointer">192                        <span id="val-stroke-width" class="text-xs font-mono text-emerald-400">2</span>193                    </div>194                </div>195                <div class="border-t border-slate-700/60 pt-3 space-y-2">196                    <div class="flex items-center justify-between">197                        <label class="text-xs text-slate-400 flex items-center gap-2">198                            <input id="chk-shadow" type="checkbox" class="rounded accent-emerald-500">199                            <span>Vektör Gölgesi (Drop Shadow)</span>200                        </label>201                        <input id="color-shadow" type="color" value="#000000" class="w-7 h-7 rounded bg-transparent cursor-pointer border-0">202                    </div>203                    <div id="section-shadow-controls" class="hidden space-y-2 pt-1">204                        <div class="flex items-center justify-between gap-2">205                            <span class="text-xs text-slate-500">Bulanıklık</span>206                            <input id="slider-shadow-blur" type="range" min="0" max="25" value="6" class="w-28 accent-emerald-500 bg-slate-700 h-1.5 rounded-lg appearance-none cursor-pointer">207                            <span id="val-shadow-blur" class="text-xs font-mono text-emerald-400">6</span>208                        </div>209                        <div class="flex items-center justify-between gap-2">210                            <span class="text-xs text-slate-500">Öteleme X</span>211                            <input id="slider-shadow-x" type="range" min="-30" max="30" value="2" class="w-28 accent-emerald-500 bg-slate-700 h-1.5 rounded-lg appearance-none cursor-pointer">212                            <span id="val-shadow-x" class="text-xs font-mono text-emerald-400">2</span>213                        </div>214                        <div class="flex items-center justify-between gap-2">215                            <span class="text-xs text-slate-500">Öteleme Y</span>216                            <input id="slider-shadow-y" type="range" min="-30" max="30" value="4" class="w-28 accent-emerald-500 bg-slate-700 h-1.5 rounded-lg appearance-none cursor-pointer">217                            <span id="val-shadow-y" class="text-xs font-mono text-emerald-400">4</span>218                        </div>219                    </div>220                </div>221            </div>222            <div class="bg-slate-800/40 border border-slate-700/80 rounded-xl p-4 space-y-3">223                <h3 class="text-xs font-semibold text-slate-300 uppercase tracking-wider border-b border-slate-700/60 pb-2 flex items-center justify-between">224                    <span>Kanvas & Arka Plan</span>225                    <i class="fa-solid fa-expand text-slate-500"></i>226                </h3>227 228                <div class="grid grid-cols-2 gap-3">229                    <div>230                        <label class="text-xs text-slate-400 block mb-1">Genişlik (px)</label>231                        <input id="canvas-width" type="number" value="650" min="100" max="3000" class="w-full bg-slate-900 border border-slate-700 rounded-lg px-3 py-1.5 text-xs text-slate-200">232                    </div>233                    <div>234                        <label class="text-xs text-slate-400 block mb-1">Yükseklik (px)</label>235                        <input id="canvas-height" type="number" value="320" min="100" max="3000" class="w-full bg-slate-900 border border-slate-700 rounded-lg px-3 py-1.5 text-xs text-slate-200">236                    </div>237                </div>238 239                <div class="flex items-center justify-between pt-2">240                    <label class="text-xs text-slate-400 flex items-center gap-2">241                        <input id="chk-bg" type="checkbox" checked class="rounded accent-emerald-500">242                        <span>Arka Plan Ekle</span>243                    </label>244                    <div id="wrapper-bg-color" class="flex items-center gap-2">245                        <input id="color-bg" type="color" value="#0f172a" class="w-7 h-7 rounded bg-transparent cursor-pointer border-0">246                        <input id="slider-bg-radius" type="number" value="16" min="0" max="100" title="Köşe Yuvarlama (rx)" class="w-14 bg-slate-900 border border-slate-700 rounded text-xs px-2 py-1 text-slate-200">247                        <span class="text-xs text-slate-500">px rx</span>248                    </div>249                </div>250            </div>251 252        </div>253        <div class="lg:col-span-7 flex flex-col gap-4 h-full">254            <div class="flex items-center justify-between bg-slate-800/60 p-2 rounded-xl border border-slate-700/60">255                <div class="flex items-center gap-1">256                    <button id="btn-view-preview" class="px-3 py-1.5 rounded-lg text-xs font-medium bg-emerald-600 text-white shadow-sm flex items-center gap-1.5">257                        <i class="fa-solid fa-eye"></i> Vektör Önizleme258                    </button>259                    <button id="btn-view-code" class="px-3 py-1.5 rounded-lg text-xs font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-800 flex items-center gap-1.5">260                        <i class="fa-solid fa-code"></i> SVG Path Kaynak Kodu261                    </button>262                </div>263 264                <div class="text-xs text-slate-400 font-mono flex items-center gap-3 px-2">265                    <span id="canvas-size-indicator">650 x 320 px</span>266                    <span class="text-slate-600">|</span>267                    <span id="svg-file-size" class="text-emerald-400">~2.5 KB</span>268                </div>269            </div>270            <div id="container-preview" class="flex-1 bg-slate-950/80 border border-slate-800 rounded-2xl p-6 flex items-center justify-center relative overflow-hidden min-h-[380px] shadow-inner">271                <div class="absolute inset-0 opacity-10 bg-[radial-gradient(#334155_1px,transparent_1px)] [background-size:16px_16px] pointer-events-none"></div>272                <div id="svg-output-wrapper" class="relative max-w-full max-h-full flex items-center justify-center transition-all duration-200">273                </div>274            </div>275            <div id="container-code" class="hidden flex-1 bg-slate-950 border border-slate-800 rounded-2xl p-4 flex flex-col min-h-[380px] relative">276                <div class="flex justify-between items-center mb-2 px-1">277                    <span class="text-xs font-mono text-emerald-400 flex items-center gap-2">278                        <i class="fa-solid fa-code"></i> Saf &lt;path d="M..." /&gt; Çıktısı (Zero Font Dependency)279                    </span>280                    <button id="btn-inner-copy" class="text-xs text-emerald-400 hover:text-emerald-300 flex items-center gap-1 bg-emerald-500/10 px-2 py-1 rounded border border-emerald-500/20">281                        <i class="fa-regular fa-copy"></i> Kopyala282                    </button>283                </div>284                <textarea id="code-output" readonly class="w-full flex-1 bg-slate-900/90 border border-slate-800 rounded-xl p-4 font-mono text-xs text-emerald-300 focus:outline-none resize-none leading-relaxed overflow-y-auto selection:bg-emerald-500/30"></textarea>285            </div>286            <div id="toast-message" class="fixed bottom-6 right-6 bg-emerald-500 text-slate-950 px-4 py-2.5 rounded-xl shadow-2xl font-medium text-xs flex items-center gap-2 transform translate-y-20 opacity-0 transition-all duration-300 pointer-events-none z-50">287                <i class="fa-solid fa-circle-check text-base"></i>288                <span id="toast-text">SVG Path kodu kopyalandı!</span>289            </div>290 291        </div>292 293    </main>294 295    <script>296        document.addEventListener('DOMContentLoaded', () => {297            const FONT_URLS = {298                'roboto-regular': 'https://cdn.jsdelivr.net/fontsource/fonts/roboto@latest/latin-400-normal.ttf',299                'roboto-bold': 'https://cdn.jsdelivr.net/fontsource/fonts/roboto@latest/latin-700-normal.ttf',300                'roboto-light': 'https://cdn.jsdelivr.net/fontsource/fonts/roboto@latest/latin-300-normal.ttf',301                'roboto-italic': 'https://cdn.jsdelivr.net/fontsource/fonts/roboto@latest/latin-400-italic.ttf',302                'noto-sans': 'https://cdn.jsdelivr.net/fontsource/fonts/noto-sans@latest/latin-400-normal.ttf',303                'roboto-mono': 'https://cdn.jsdelivr.net/fontsource/fonts/roboto-mono@latest/latin-400-normal.ttf'304            };305 306            const state = {307                text: "Android OS\nSystem Vector",308                fontPreset: "roboto-regular",309                currentFont: null,310                isLoadingFont: true,311                fontSize: 56,312                lineHeight: 1.2,313                letterSpacing: 0,314                textAlign: "center",315                fillType: "solid",316                colorText: "#38bdf8",317                colorGrad1: "#38bdf8",318                colorGrad2: "#34d399",319                gradAngle: "horizontal",320                hasStroke: false,321                colorStroke: "#0f172a",322                strokeWidth: 2,323                hasShadow: false,324                colorShadow: "#000000",325                shadowBlur: 6,326                shadowX: 2,327                shadowY: 4,328                width: 650,329                height: 320,330                hasBg: true,331                colorBg: "#0f172a",332                bgRadius: 16333            };334            const inputText = document.getElementById('input-text');335            const selectFontPreset = document.getElementById('select-font-preset');336            const sectionCustomFont = document.getElementById('section-custom-font');337            const fileCustomFont = document.getElementById('file-custom-font');338            const fontLoadingStatus = document.getElementById('font-loading-status');339 340            const sliderFontSize = document.getElementById('slider-font-size');341            const valFontSize = document.getElementById('val-font-size');342            const sliderLineHeight = document.getElementById('slider-line-height');343            const valLineHeight = document.getElementById('val-line-height');344            const sliderLetterSpacing = document.getElementById('slider-letter-spacing');345            const valLetterSpacing = document.getElementById('val-letter-spacing');346            const btnAligns = document.querySelectorAll('.btn-align');347 348            const tabSolid = document.getElementById('tab-fill-solid');349            const tabGradient = document.getElementById('tab-fill-gradient');350            const sectionSolid = document.getElementById('section-fill-solid');351            const sectionGradient = document.getElementById('section-fill-gradient');352 353            const colorText = document.getElementById('color-text');354            const hexText = document.getElementById('hex-text');355            const colorGrad1 = document.getElementById('color-grad-1');356            const colorGrad2 = document.getElementById('color-grad-2');357            const selectGradAngle = document.getElementById('select-grad-angle');358 359            const chkStroke = document.getElementById('chk-stroke');360            const sectionStrokeWidth = document.getElementById('section-stroke-width');361            const colorStroke = document.getElementById('color-stroke');362            const sliderStrokeWidth = document.getElementById('slider-stroke-width');363            const valStrokeWidth = document.getElementById('val-stroke-width');364 365            const chkShadow = document.getElementById('chk-shadow');366            const sectionShadowControls = document.getElementById('section-shadow-controls');367            const colorShadow = document.getElementById('color-shadow');368            const sliderShadowBlur = document.getElementById('slider-shadow-blur');369            const valShadowBlur = document.getElementById('val-shadow-blur');370            const sliderShadowX = document.getElementById('slider-shadow-x');371            const valShadowX = document.getElementById('val-shadow-x');372            const sliderShadowY = document.getElementById('slider-shadow-y');373            const valShadowY = document.getElementById('val-shadow-y');374 375            const inputWidth = document.getElementById('canvas-width');376            const inputHeight = document.getElementById('canvas-height');377            const chkBg = document.getElementById('chk-bg');378            const colorBg = document.getElementById('color-bg');379            const sliderBgRadius = document.getElementById('slider-bg-radius');380            const wrapperBgColor = document.getElementById('wrapper-bg-color');381 382            const svgOutputWrapper = document.getElementById('svg-output-wrapper');383            const codeOutput = document.getElementById('code-output');384            const canvasSizeIndicator = document.getElementById('canvas-size-indicator');385            const svgFileSize = document.getElementById('svg-file-size');386 387            const btnViewPreview = document.getElementById('btn-view-preview');388            const btnViewCode = document.getElementById('btn-view-code');389            const containerPreview = document.getElementById('container-preview');390            const containerCode = document.getElementById('container-code');391 392            const btnExportSvg = document.getElementById('btn-export-svg');393            const btnCopyCode = document.getElementById('btn-copy-code');394            const btnInnerCopy = document.getElementById('btn-inner-copy');395            const toastMessage = document.getElementById('toast-message');396            const toastText = document.getElementById('toast-text');397            function loadPresetFont(key) {398                const url = FONT_URLS[key];399                if (!url) return;400 401                state.isLoadingFont = true;402                updateStatusUI("loading", "Font indiriliyor & işleniyor...");403 404                opentype.load(url, (err, font) => {405                    if (err) {406                        console.error("Font yükleme hatası:", err);407                        updateStatusUI("error", "Font yüklenemedi. Lütfen tekrar deneyin.");408                        state.isLoadingFont = false;409                        return;410                    }411                    state.currentFont = font;412                    state.isLoadingFont = false;413                    updateStatusUI("success", `Font hazır: ${font.names.fontFamily?.en || key}`);414                    renderSVG();415                });416            }417 418            function updateStatusUI(type, message) {419                if (type === "loading") {420                    fontLoadingStatus.className = "flex items-center gap-2 text-xs text-amber-400 font-mono";421                    fontLoadingStatus.innerHTML = `<i class="fa-solid fa-spinner fa-spin"></i> <span>${message}</span>`;422                } else if (type === "success") {423                    fontLoadingStatus.className = "flex items-center gap-2 text-xs text-emerald-400 font-mono";424                    fontLoadingStatus.innerHTML = `<i class="fa-solid fa-check"></i> <span>${message}</span>`;425                } else if (type === "error") {426                    fontLoadingStatus.className = "flex items-center gap-2 text-xs text-rose-400 font-mono";427                    fontLoadingStatus.innerHTML = `<i class="fa-solid fa-triangle-exclamation"></i> <span>${message}</span>`;428                }429            }430            function generateCombinedPathData() {431                if (!state.currentFont) return "";432 433                const font = state.currentFont;434                const lines = state.text.split('\n');435                const fontSize = state.fontSize;436                const lineGap = fontSize * state.lineHeight;437                const letterSpacing = state.letterSpacing;438                const totalTextHeight = lines.length * lineGap;439                const startY = (state.height / 2) - (totalTextHeight / 2) + (fontSize * 0.7);440 441                let combinedPathCommands = "";442 443                lines.forEach((lineText, lineIdx) => {444                    if (!lineText) lineText = " ";445                    const yPos = startY + (lineIdx * lineGap);446                    let lineWidth = 0;447                    const glyphs = font.stringToGlyphs(lineText);448                    449                    for (let i = 0; i < glyphs.length; i++) {450                        const glyph = glyphs[i];451                        if (glyph.advanceWidth) {452                            lineWidth += (glyph.advanceWidth / font.unitsPerEm) * fontSize;453                        }454                        if (i < glyphs.length - 1) {455                            lineWidth += letterSpacing;456                        }457                    }458 459                    let xPos = 0;460                    if (state.textAlign === 'left') {461                        xPos = state.width * 0.08;462                    } else if (state.textAlign === 'center') {463                        xPos = (state.width - lineWidth) / 2;464                    } else if (state.textAlign === 'right') {465                        xPos = state.width * 0.92 - lineWidth;466                    }467 468                    let currentX = xPos;469                    for (let i = 0; i < glyphs.length; i++) {470                        const glyph = glyphs[i];471                        const glyphPath = glyph.getPath(currentX, yPos, fontSize);472                        combinedPathCommands += glyphPath.toPathData() + " ";473 474                        if (glyph.advanceWidth) {475                            currentX += (glyph.advanceWidth / font.unitsPerEm) * fontSize;476                        }477                        currentX += letterSpacing;478                    }479                });480 481                return combinedPathCommands.trim();482            }483            function buildSVGString() {484                if (state.isLoadingFont || !state.currentFont) {485                    return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${state.width} ${state.height}" width="${state.width}" height="${state.height}">486  <text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" fill="#38bdf8" font-family="sans-serif" font-size="16">Font Yükleniyor...</text>487</svg>`;488                }489 490                const pathData = generateCombinedPathData();491                let defsMarkup = "";492                let fillAttr = state.colorText;493 494                if (state.fillType === 'gradient') {495                    let x1 = "0%", y1 = "0%", x2 = "100%", y2 = "0%";496                    if (state.gradAngle === 'vertical') {497                        x1 = "0%"; y1 = "0%"; x2 = "0%"; y2 = "100%";498                    } else if (state.gradAngle === 'diagonal') {499                        x1 = "0%"; y1 = "0%"; x2 = "100%"; y2 = "100%";500                    }501 502                    defsMarkup += `503    <linearGradient id="androidPathGrad" x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}">504      <stop offset="0%" stop-color="${state.colorGrad1}" />505      <stop offset="100%" stop-color="${state.colorGrad2}" />506    </linearGradient>`;507                    fillAttr = "url(#androidPathGrad)";508                }509 510                if (state.hasShadow) {511                    defsMarkup += `512    <filter id="pathDropShadow" x="-30%" y="-30%" width="160%" height="160%">513      <feDropShadow dx="${state.shadowX}" dy="${state.shadowY}" stdDeviation="${state.shadowBlur / 2}" flood-color="${state.colorShadow}" flood-opacity="0.8"/>514    </filter>`;515                }516 517                const defsBlock = defsMarkup ? `\n  <defs>${defsMarkup}\n  </defs>\n` : "";518                let bgRect = "";519                if (state.hasBg) {520                    bgRect = `\n  <!-- Background Rect -->\n  <rect width="100%" height="100%" fill="${state.colorBg}" rx="${state.bgRadius}" ry="${state.bgRadius}" />\n`;521                }522 523                let strokeAttrs = "";524                if (state.hasStroke) {525                    strokeAttrs = ` stroke="${state.colorStroke}" stroke-width="${state.strokeWidth}" stroke-linejoin="round" stroke-linecap="round"`;526                }527 528                let filterAttr = "";529                if (state.hasShadow) {530                    filterAttr = ` filter="url(#pathDropShadow)"`;531                }532 533                const svgString = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${state.width} ${state.height}" width="${state.width}" height="${state.height}">534  <!-- Converted to Real SVG Path curves via Opentype.js -->${defsBlock}${bgRect}535  <path d="${pathData}"536        fill="${fillAttr}"${strokeAttrs}${filterAttr} />537</svg>`;538 539                return svgString;540            }541 542            function renderSVG() {543                const svgCode = buildSVGString();544                svgOutputWrapper.innerHTML = svgCode;545                codeOutput.value = svgCode;546 547                canvasSizeIndicator.textContent = `${state.width} x ${state.height} px`;548                const bytes = new Blob([svgCode]).size;549                svgFileSize.textContent = bytes > 1024 ? `~${(bytes / 1024).toFixed(1)} KB` : `~${bytes} B`;550            }551 552            function showToast(msg) {553                toastText.textContent = msg;554                toastMessage.classList.remove('translate-y-20', 'opacity-0');555                toastMessage.classList.add('translate-y-0', 'opacity-100');556                setTimeout(() => {557                    toastMessage.classList.remove('translate-y-0', 'opacity-100');558                    toastMessage.classList.add('translate-y-20', 'opacity-0');559                }, 2500);560            }561 562            inputText.addEventListener('input', (e) => {563                state.text = e.target.value;564                renderSVG();565            });566 567            selectFontPreset.addEventListener('change', (e) => {568                const val = e.target.value;569                state.fontPreset = val;570 571                if (val === 'custom') {572                    sectionCustomFont.classList.remove('hidden');573                } else {574                    sectionCustomFont.classList.add('hidden');575                    loadPresetFont(val);576                }577            });578 579            fileCustomFont.addEventListener('change', (e) => {580                const file = e.target.files[0];581                if (!file) return;582 583                const reader = new FileReader();584                updateStatusUI("loading", "Özel font okunuyor...");585 586                reader.onload = function (evt) {587                    try {588                        const font = opentype.parse(evt.target.result);589                        state.currentFont = font;590                        state.isLoadingFont = false;591                        updateStatusUI("success", `Özel Font: ${font.names.fontFamily?.en || file.name}`);592                        renderSVG();593                    } catch (err) {594                        console.error(err);595                        updateStatusUI("error", "Geçersiz font dosyası!");596                    }597                };598 599                reader.readAsArrayBuffer(file);600            });601 602            sliderFontSize.addEventListener('input', (e) => {603                state.fontSize = parseInt(e.target.value, 10);604                valFontSize.textContent = state.fontSize;605                renderSVG();606            });607 608            sliderLineHeight.addEventListener('input', (e) => {609                state.lineHeight = parseFloat(e.target.value);610                valLineHeight.textContent = state.lineHeight;611                renderSVG();612            });613 614            sliderLetterSpacing.addEventListener('input', (e) => {615                state.letterSpacing = parseInt(e.target.value, 10);616                valLetterSpacing.textContent = state.letterSpacing;617                renderSVG();618            });619 620            btnAligns.forEach(btn => {621                btn.addEventListener('click', () => {622                    btnAligns.forEach(b => {623                        b.classList.remove('bg-emerald-600', 'text-white', 'border-emerald-500');624                        b.classList.add('bg-slate-800', 'text-slate-300', 'border-slate-700');625                    });626                    btn.classList.remove('bg-slate-800', 'text-slate-300', 'border-slate-700');627                    btn.classList.add('bg-emerald-600', 'text-white', 'border-emerald-500');628 629                    state.textAlign = btn.getAttribute('data-align');630                    renderSVG();631                });632            });633 634            tabSolid.addEventListener('click', () => {635                tabSolid.className = "py-1.5 text-xs rounded-lg bg-emerald-600 text-white border border-emerald-500 font-medium";636                tabGradient.className = "py-1.5 text-xs rounded-lg bg-slate-800 text-slate-300 hover:bg-slate-700 border border-slate-700 font-medium";637                sectionSolid.classList.remove('hidden');638                sectionGradient.classList.add('hidden');639                state.fillType = 'solid';640                renderSVG();641            });642 643            tabGradient.addEventListener('click', () => {644                tabGradient.className = "py-1.5 text-xs rounded-lg bg-emerald-600 text-white border border-emerald-500 font-medium";645                tabSolid.className = "py-1.5 text-xs rounded-lg bg-slate-800 text-slate-300 hover:bg-slate-700 border border-slate-700 font-medium";646                sectionGradient.classList.remove('hidden');647                sectionSolid.classList.add('hidden');648                state.fillType = 'gradient';649                renderSVG();650            });651 652            colorText.addEventListener('input', (e) => {653                state.colorText = e.target.value;654                hexText.value = e.target.value;655                renderSVG();656            });657 658            hexText.addEventListener('input', (e) => {659                if (/^#[0-9A-F]{6}$/i.test(e.target.value)) {660                    state.colorText = e.target.value;661                    colorText.value = e.target.value;662                    renderSVG();663                }664            });665 666            colorGrad1.addEventListener('input', (e) => {667                state.colorGrad1 = e.target.value;668                renderSVG();669            });670 671            colorGrad2.addEventListener('input', (e) => {672                state.colorGrad2 = e.target.value;673                renderSVG();674            });675 676            selectGradAngle.addEventListener('change', (e) => {677                state.gradAngle = e.target.value;678                renderSVG();679            });680 681            chkStroke.addEventListener('change', (e) => {682                state.hasStroke = e.target.checked;683                sectionStrokeWidth.classList.toggle('hidden', !e.target.checked);684                renderSVG();685            });686 687            colorStroke.addEventListener('input', (e) => {688                state.colorStroke = e.target.value;689                renderSVG();690            });691 692            sliderStrokeWidth.addEventListener('input', (e) => {693                state.strokeWidth = parseInt(e.target.value, 10);694                valStrokeWidth.textContent = state.strokeWidth;695                renderSVG();696            });697 698            chkShadow.addEventListener('change', (e) => {699                state.hasShadow = e.target.checked;700                sectionShadowControls.classList.toggle('hidden', !e.target.checked);701                renderSVG();702            });703 704            colorShadow.addEventListener('input', (e) => {705                state.colorShadow = e.target.value;706                renderSVG();707            });708 709            sliderShadowBlur.addEventListener('input', (e) => {710                state.shadowBlur = parseInt(e.target.value, 10);711                valShadowBlur.textContent = state.shadowBlur;712                renderSVG();713            });714 715            sliderShadowX.addEventListener('input', (e) => {716                state.shadowX = parseInt(e.target.value, 10);717                valShadowX.textContent = state.shadowX;718                renderSVG();719            });720 721            sliderShadowY.addEventListener('input', (e) => {722                state.shadowY = parseInt(e.target.value, 10);723                valShadowY.textContent = state.shadowY;724                renderSVG();725            });726 727            // Canvas Dimensions728            inputWidth.addEventListener('input', (e) => {729                state.width = Math.max(100, parseInt(e.target.value, 10) || 100);730                renderSVG();731            });732 733            inputHeight.addEventListener('input', (e) => {734                state.height = Math.max(100, parseInt(e.target.value, 10) || 100);735                renderSVG();736            });737 738            chkBg.addEventListener('change', (e) => {739                state.hasBg = e.target.checked;740                wrapperBgColor.classList.toggle('opacity-40', !e.target.checked);741                wrapperBgColor.classList.toggle('pointer-events-none', !e.target.checked);742                renderSVG();743            });744 745            colorBg.addEventListener('input', (e) => {746                state.colorBg = e.target.value;747                renderSVG();748            });749 750            sliderBgRadius.addEventListener('input', (e) => {751                state.bgRadius = Math.max(0, parseInt(e.target.value, 10) || 0);752                renderSVG();753            });754 755            btnViewPreview.addEventListener('click', () => {756                btnViewPreview.className = "px-3 py-1.5 rounded-lg text-xs font-medium bg-emerald-600 text-white shadow-sm flex items-center gap-1.5";757                btnViewCode.className = "px-3 py-1.5 rounded-lg text-xs font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-800 flex items-center gap-1.5";758                containerPreview.classList.remove('hidden');759                containerCode.classList.add('hidden');760            });761 762            btnViewCode.addEventListener('click', () => {763                btnViewCode.className = "px-3 py-1.5 rounded-lg text-xs font-medium bg-emerald-600 text-white shadow-sm flex items-center gap-1.5";764                btnViewPreview.className = "px-3 py-1.5 rounded-lg text-xs font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-800 flex items-center gap-1.5";765                containerCode.classList.remove('hidden');766                containerPreview.classList.add('hidden');767            });768 769            function copyToClipboard(text) {770                const textarea = document.createElement('textarea');771                textarea.value = text;772                textarea.style.position = 'fixed';773                textarea.style.left = '-9999px';774                document.body.appendChild(textarea);775                textarea.select();776                try {777                    document.execCommand('copy');778                    showToast("SVG Path kodu panoya kopyalandı!");779                } catch (err) {780                    showToast("Kopyalama başarısız oldu.");781                }782                document.body.removeChild(textarea);783            }784 785            btnCopyCode.addEventListener('click', () => copyToClipboard(buildSVGString()));786            btnInnerCopy.addEventListener('click', () => copyToClipboard(buildSVGString()));787 788            btnExportSvg.addEventListener('click', () => {789                const svgContent = buildSVGString();790                const blob = new Blob([svgContent], { type: 'image/svg+xml;charset=utf-8' });791                const url = URL.createObjectURL(blob);792 793                const link = document.createElement('a');794                link.href = url;795                link.download = `android-vector-path-${Date.now()}.svg`;796                document.body.appendChild(link);797                link.click();798                document.body.removeChild(link);799                URL.revokeObjectURL(url);800 801                showToast("SVG dosyası başarıyla indirildi!");802            });803            loadPresetFont('roboto-regular');804        });805    </script>806</body>807</html>