I want it all in Spanish even more high tech and called simply >_teleprompter
Browse files- components/footer.js +16 -19
- components/navbar.js +9 -12
- index.html +45 -51
- script.js +73 -97
components/footer.js
CHANGED
|
@@ -10,7 +10,6 @@ class CustomFooter extends HTMLElement {
|
|
| 10 |
padding: 2rem 0;
|
| 11 |
margin-top: 3rem;
|
| 12 |
}
|
| 13 |
-
|
| 14 |
.footer-container {
|
| 15 |
max-width: 1200px;
|
| 16 |
margin: 0 auto;
|
|
@@ -63,21 +62,19 @@ class CustomFooter extends HTMLElement {
|
|
| 63 |
color: rgba(255, 255, 255, 0.4);
|
| 64 |
font-size: 0.9rem;
|
| 65 |
}
|
| 66 |
-
|
| 67 |
-
@media (max-width: 768px) {
|
| 68 |
.footer-container {
|
| 69 |
grid-template-columns: 1fr;
|
| 70 |
padding: 0 1rem;
|
| 71 |
}
|
| 72 |
}
|
| 73 |
</style>
|
| 74 |
-
|
| 75 |
<footer>
|
| 76 |
<div class="footer-container">
|
| 77 |
<div class="footer-section">
|
| 78 |
-
<h3>
|
| 79 |
<p style="color: rgba(255, 255, 255, 0.6); line-height: 1.5;">
|
| 80 |
-
|
| 81 |
</p>
|
| 82 |
<div class="social-links">
|
| 83 |
<a href="#" class="social-link"><i data-feather="twitter"></i></a>
|
|
@@ -87,20 +84,20 @@ class CustomFooter extends HTMLElement {
|
|
| 87 |
</div>
|
| 88 |
</div>
|
| 89 |
<div class="footer-section">
|
| 90 |
-
<h3>
|
| 91 |
<div class="footer-links">
|
| 92 |
-
<a href="/" class="footer-link">
|
| 93 |
-
<a href="/features" class="footer-link">
|
| 94 |
-
<a href="/pricing" class="footer-link">
|
| 95 |
-
<a href="/templates" class="footer-link">
|
| 96 |
</div>
|
| 97 |
</div>
|
| 98 |
<div class="footer-section">
|
| 99 |
-
<h3>
|
| 100 |
<div class="footer-links">
|
| 101 |
<a href="/blog" class="footer-link">Blog</a>
|
| 102 |
-
<a href="/tutorials" class="footer-link">
|
| 103 |
-
<a href="/support" class="footer-link">
|
| 104 |
<a href="/faq" class="footer-link">FAQ</a>
|
| 105 |
</div>
|
| 106 |
</div>
|
|
@@ -108,18 +105,18 @@ class CustomFooter extends HTMLElement {
|
|
| 108 |
<div class="footer-section">
|
| 109 |
<h3>Legal</h3>
|
| 110 |
<div class="footer-links">
|
| 111 |
-
<a href="/privacy" class="footer-link">
|
| 112 |
-
<a href="/terms" class="footer-link">
|
| 113 |
-
<a href="/cookies" class="footer-link">
|
| 114 |
</div>
|
| 115 |
</div>
|
| 116 |
</div>
|
| 117 |
|
| 118 |
<div class="copyright">
|
| 119 |
-
© ${new Date().getFullYear()}
|
| 120 |
</div>
|
| 121 |
</footer>
|
| 122 |
-
|
| 123 |
}
|
| 124 |
}
|
| 125 |
|
|
|
|
| 10 |
padding: 2rem 0;
|
| 11 |
margin-top: 3rem;
|
| 12 |
}
|
|
|
|
| 13 |
.footer-container {
|
| 14 |
max-width: 1200px;
|
| 15 |
margin: 0 auto;
|
|
|
|
| 62 |
color: rgba(255, 255, 255, 0.4);
|
| 63 |
font-size: 0.9rem;
|
| 64 |
}
|
| 65 |
+
@media (max-width: 768px) {
|
|
|
|
| 66 |
.footer-container {
|
| 67 |
grid-template-columns: 1fr;
|
| 68 |
padding: 0 1rem;
|
| 69 |
}
|
| 70 |
}
|
| 71 |
</style>
|
|
|
|
| 72 |
<footer>
|
| 73 |
<div class="footer-container">
|
| 74 |
<div class="footer-section">
|
| 75 |
+
<h3>>_teleprompter</h3>
|
| 76 |
<p style="color: rgba(255, 255, 255, 0.6); line-height: 1.5;">
|
| 77 |
+
Software profesional de teleprompter para presentadores, emisoras y creadores de contenido.
|
| 78 |
</p>
|
| 79 |
<div class="social-links">
|
| 80 |
<a href="#" class="social-link"><i data-feather="twitter"></i></a>
|
|
|
|
| 84 |
</div>
|
| 85 |
</div>
|
| 86 |
<div class="footer-section">
|
| 87 |
+
<h3>Enlaces Rápidos</h3>
|
| 88 |
<div class="footer-links">
|
| 89 |
+
<a href="/" class="footer-link">Inicio</a>
|
| 90 |
+
<a href="/features" class="footer-link">Características</a>
|
| 91 |
+
<a href="/pricing" class="footer-link">Precios</a>
|
| 92 |
+
<a href="/templates" class="footer-link">Plantillas</a>
|
| 93 |
</div>
|
| 94 |
</div>
|
| 95 |
<div class="footer-section">
|
| 96 |
+
<h3>Recursos</h3>
|
| 97 |
<div class="footer-links">
|
| 98 |
<a href="/blog" class="footer-link">Blog</a>
|
| 99 |
+
<a href="/tutorials" class="footer-link">Tutoriales</a>
|
| 100 |
+
<a href="/support" class="footer-link">Soporte</a>
|
| 101 |
<a href="/faq" class="footer-link">FAQ</a>
|
| 102 |
</div>
|
| 103 |
</div>
|
|
|
|
| 105 |
<div class="footer-section">
|
| 106 |
<h3>Legal</h3>
|
| 107 |
<div class="footer-links">
|
| 108 |
+
<a href="/privacy" class="footer-link">Política de Privacidad</a>
|
| 109 |
+
<a href="/terms" class="footer-link">Términos de Servicio</a>
|
| 110 |
+
<a href="/cookies" class="footer-link">Política de Cookies</a>
|
| 111 |
</div>
|
| 112 |
</div>
|
| 113 |
</div>
|
| 114 |
|
| 115 |
<div class="copyright">
|
| 116 |
+
© ${new Date().getFullYear()} >_teleprompter. Todos los derechos reservados.
|
| 117 |
</div>
|
| 118 |
</footer>
|
| 119 |
+
`;
|
| 120 |
}
|
| 121 |
}
|
| 122 |
|
components/navbar.js
CHANGED
|
@@ -17,7 +17,6 @@ class CustomNavbar extends HTMLElement {
|
|
| 17 |
justify-content: space-between;
|
| 18 |
align-items: center;
|
| 19 |
}
|
| 20 |
-
|
| 21 |
.logo {
|
| 22 |
font-weight: 700;
|
| 23 |
font-size: 1.25rem;
|
|
@@ -40,8 +39,7 @@ class CustomNavbar extends HTMLElement {
|
|
| 40 |
.nav-link:hover {
|
| 41 |
color: white;
|
| 42 |
}
|
| 43 |
-
|
| 44 |
-
@media (max-width: 768px) {
|
| 45 |
.nav-container {
|
| 46 |
flex-direction: column;
|
| 47 |
padding: 1rem;
|
|
@@ -54,23 +52,22 @@ class CustomNavbar extends HTMLElement {
|
|
| 54 |
}
|
| 55 |
}
|
| 56 |
</style>
|
| 57 |
-
|
| 58 |
<nav>
|
| 59 |
<div class="nav-container">
|
| 60 |
<a href="/" class="logo">
|
| 61 |
-
<i data-feather="
|
| 62 |
-
|
| 63 |
</a>
|
| 64 |
<div class="nav-links">
|
| 65 |
-
<a href="/" class="nav-link">
|
| 66 |
-
<a href="/templates" class="nav-link">
|
| 67 |
-
<a href="/features" class="nav-link">
|
| 68 |
-
<a href="/pricing" class="nav-link">
|
| 69 |
-
<a href="/contact" class="nav-link">
|
| 70 |
</div>
|
| 71 |
</div>
|
| 72 |
</nav>
|
| 73 |
-
|
| 74 |
}
|
| 75 |
}
|
| 76 |
|
|
|
|
| 17 |
justify-content: space-between;
|
| 18 |
align-items: center;
|
| 19 |
}
|
|
|
|
| 20 |
.logo {
|
| 21 |
font-weight: 700;
|
| 22 |
font-size: 1.25rem;
|
|
|
|
| 39 |
.nav-link:hover {
|
| 40 |
color: white;
|
| 41 |
}
|
| 42 |
+
@media (max-width: 768px) {
|
|
|
|
| 43 |
.nav-container {
|
| 44 |
flex-direction: column;
|
| 45 |
padding: 1rem;
|
|
|
|
| 52 |
}
|
| 53 |
}
|
| 54 |
</style>
|
|
|
|
| 55 |
<nav>
|
| 56 |
<div class="nav-container">
|
| 57 |
<a href="/" class="logo">
|
| 58 |
+
<i data-feather="terminal"></i>
|
| 59 |
+
>_teleprompter
|
| 60 |
</a>
|
| 61 |
<div class="nav-links">
|
| 62 |
+
<a href="/" class="nav-link">Inicio</a>
|
| 63 |
+
<a href="/templates" class="nav-link">Plantillas</a>
|
| 64 |
+
<a href="/features" class="nav-link">Características</a>
|
| 65 |
+
<a href="/pricing" class="nav-link">Precios</a>
|
| 66 |
+
<a href="/contact" class="nav-link">Contacto</a>
|
| 67 |
</div>
|
| 68 |
</div>
|
| 69 |
</nav>
|
| 70 |
+
`;
|
| 71 |
}
|
| 72 |
}
|
| 73 |
|
index.html
CHANGED
|
@@ -3,8 +3,8 @@
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
-
<title>
|
| 7 |
-
|
| 8 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
<script src="https://unpkg.com/feather-icons"></script>
|
| 10 |
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
|
@@ -42,50 +42,47 @@
|
|
| 42 |
<i data-feather="x" class="w-4 h-4"></i>
|
| 43 |
</button>
|
| 44 |
</div>
|
| 45 |
-
<h1 class="text-3xl font-bold">
|
| 46 |
-
<p class="text-gray-200 mt-2">
|
| 47 |
</div>
|
| 48 |
-
|
| 49 |
<div class="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-primary-500 to-secondary-500"></div>
|
| 50 |
<div class="lg:col-span-1 space-y-6">
|
| 51 |
<div>
|
| 52 |
<label class="block text-sm font-medium text-gray-300 mb-1 flex items-center justify-between">
|
| 53 |
-
<span>
|
| 54 |
<span class="text-xs text-gray-400">Ctrl+T</span>
|
| 55 |
</label>
|
| 56 |
<div class="relative">
|
| 57 |
-
<input type="text" id="script-title" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:ring-2 focus:ring-primary-500 focus:border-primary-500 outline-none transition pr-10" placeholder="
|
| 58 |
<button class="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-white">
|
| 59 |
<i data-feather="edit-2" class="w-4 h-4"></i>
|
| 60 |
</button>
|
| 61 |
</div>
|
| 62 |
</div>
|
| 63 |
-
|
| 64 |
<div>
|
| 65 |
<label class="block text-sm font-medium text-gray-300 mb-1 flex items-center justify-between">
|
| 66 |
-
<span>
|
| 67 |
<span class="text-xs text-gray-400" id="speed-value">1.0x</span>
|
| 68 |
</label>
|
| 69 |
<input type="range" id="speed-slider" min="0.1" max="5" step="0.1" value="1" class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-primary-500">
|
| 70 |
<div class="flex justify-between text-xs text-gray-400 mt-1">
|
| 71 |
-
<span>
|
| 72 |
-
<span>
|
| 73 |
-
<span>
|
| 74 |
</div>
|
| 75 |
</div>
|
| 76 |
-
|
| 77 |
<div>
|
| 78 |
-
<label class="block text-sm font-medium text-gray-300 mb-1">
|
| 79 |
<select id="text-size" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:ring-2 focus:ring-primary-500 focus:border-primary-500 outline-none transition">
|
| 80 |
-
<option value="small">
|
| 81 |
-
<option value="medium" selected>
|
| 82 |
-
<option value="large">
|
| 83 |
-
<option value="x-large">Extra
|
| 84 |
</select>
|
| 85 |
</div>
|
| 86 |
-
|
| 87 |
<div>
|
| 88 |
-
<label class="block text-sm font-medium text-gray-300 mb-1">
|
| 89 |
<div class="grid grid-cols-3 gap-2 theme-selector">
|
| 90 |
<button class="bg-blue-500 h-10 rounded-lg theme-btn active" data-theme="blue"></button>
|
| 91 |
<button class="bg-green-500 h-10 rounded-lg theme-btn" data-theme="green"></button>
|
|
@@ -95,9 +92,8 @@
|
|
| 95 |
<button class="bg-pink-500 h-10 rounded-lg theme-btn" data-theme="pink"></button>
|
| 96 |
</div>
|
| 97 |
</div>
|
| 98 |
-
|
| 99 |
<div>
|
| 100 |
-
<label class="block text-sm font-medium text-gray-300 mb-1">
|
| 101 |
<div class="grid grid-cols-3 gap-2">
|
| 102 |
<button id="align-left" class="p-2 bg-gray-700 rounded-lg hover:bg-gray-600 flex items-center justify-center">
|
| 103 |
<i data-feather="align-left" class="w-4 h-4"></i>
|
|
@@ -110,88 +106,86 @@
|
|
| 110 |
</button>
|
| 111 |
</div>
|
| 112 |
</div>
|
| 113 |
-
|
| 114 |
<div>
|
| 115 |
-
<label class="block text-sm font-medium text-gray-300 mb-1">
|
| 116 |
<div class="grid grid-cols-2 gap-2">
|
| 117 |
<button id="font-sans" class="p-2 bg-gray-700 rounded-lg hover:bg-gray-600 active">Sans Serif</button>
|
| 118 |
<button id="font-serif" class="p-2 bg-gray-700 rounded-lg hover:bg-gray-600">Serif</button>
|
| 119 |
</div>
|
| 120 |
</div>
|
| 121 |
-
|
| 122 |
|
| 123 |
<div class="lg:col-span-2 flex flex-col gap-4">
|
| 124 |
<div class="bg-gray-700 rounded-lg p-4 flex-grow relative group">
|
| 125 |
<div class="absolute top-2 right-2 flex gap-1 z-10">
|
| 126 |
-
<button id="format-bold" class="p-1 bg-gray-600 rounded hover:bg-gray-500" title="
|
| 127 |
<i data-feather="bold" class="w-4 h-4"></i>
|
| 128 |
</button>
|
| 129 |
-
<button id="format-italic" class="p-1 bg-gray-600 rounded hover:bg-gray-500" title="
|
| 130 |
<i data-feather="italic" class="w-4 h-4"></i>
|
| 131 |
</button>
|
| 132 |
-
<button id="format-underline" class="p-1 bg-gray-600 rounded hover:bg-gray-500" title="
|
| 133 |
<i data-feather="underline" class="w-4 h-4"></i>
|
| 134 |
</button>
|
| 135 |
</div>
|
| 136 |
-
<textarea id="script-textarea" class="w-full h-64 bg-transparent resize-none outline-none text-gray-200 placeholder-gray-500" placeholder="
|
| 137 |
|
| 138 |
-
|
| 139 |
|
| 140 |
-
•
|
| 141 |
-
•
|
| 142 |
-
•
|
| 143 |
-
•
|
| 144 |
-
•
|
| 145 |
|
| 146 |
-
|
| 147 |
<div class="absolute bottom-4 right-4 opacity-0 group-hover:opacity-100 transition flex gap-2">
|
| 148 |
-
<button id="import-script" class="p-2 bg-gray-600 rounded-lg hover:bg-gray-500" title="
|
| 149 |
<i data-feather="upload" class="w-4 h-4"></i>
|
| 150 |
</button>
|
| 151 |
-
<button id="clear-script" class="p-2 bg-gray-600 rounded-lg hover:bg-gray-500" title="
|
| 152 |
<i data-feather="trash-2" class="w-4 h-4"></i>
|
| 153 |
</button>
|
| 154 |
</div>
|
| 155 |
</div>
|
| 156 |
-
|
| 157 |
<div class="bg-gray-700 rounded-lg p-4">
|
| 158 |
<div class="flex justify-between items-center mb-2">
|
| 159 |
-
<h3 class="font-medium">
|
| 160 |
<div class="flex gap-2">
|
| 161 |
-
<button id="toggle-preview" class="px-3 py-1 bg-gray-600 hover:bg-gray-500 rounded text-sm">
|
| 162 |
-
<button id="mirror-preview" class="px-3 py-1 bg-gray-600 hover:bg-gray-500 rounded text-sm">
|
| 163 |
</div>
|
| 164 |
</div>
|
| 165 |
<div id="preview-container" class="bg-black rounded p-4 h-40 overflow-hidden relative">
|
| 166 |
<div id="preview-text" class="text-white text-center text-lg leading-relaxed">
|
| 167 |
-
|
| 168 |
</div>
|
| 169 |
</div>
|
| 170 |
</div>
|
| 171 |
-
|
| 172 |
</div>
|
| 173 |
|
| 174 |
<div class="p-6 bg-gray-700 border-t border-gray-600 flex flex-wrap justify-between gap-4">
|
| 175 |
<div class="flex gap-2">
|
| 176 |
<button id="save-script" class="px-4 py-2 bg-gray-600 hover:bg-gray-500 rounded-lg font-medium transition flex items-center gap-2 text-sm">
|
| 177 |
-
<i data-feather="save" class="w-4 h-4"></i>
|
| 178 |
</button>
|
| 179 |
<button id="load-script" class="px-4 py-2 bg-gray-600 hover:bg-gray-500 rounded-lg font-medium transition flex items-center gap-2 text-sm">
|
| 180 |
-
<i data-feather="folder" class="w-4 h-4"></i>
|
| 181 |
</button>
|
| 182 |
<button id="export-script" class="px-4 py-2 bg-gray-600 hover:bg-gray-500 rounded-lg font-medium transition flex items-center gap-2 text-sm">
|
| 183 |
-
<i data-feather="download" class="w-4 h-4"></i>
|
| 184 |
</button>
|
| 185 |
</div>
|
| 186 |
<div class="flex gap-2">
|
| 187 |
<button id="help-btn" class="px-4 py-2 bg-gray-600 hover:bg-gray-500 rounded-lg font-medium transition flex items-center gap-2 text-sm">
|
| 188 |
-
<i data-feather="help-circle" class="w-4 h-4"></i>
|
| 189 |
</button>
|
| 190 |
<button id="start-scroll" class="px-6 py-2 bg-primary-500 hover:bg-primary-600 rounded-lg font-medium transition flex items-center gap-2 text-sm glow">
|
| 191 |
-
<i data-feather="play" class="w-4 h-4"></i>
|
| 192 |
</button>
|
| 193 |
</div>
|
| 194 |
-
|
| 195 |
</div>
|
| 196 |
</main>
|
| 197 |
|
|
@@ -199,7 +193,7 @@ Try adjusting the scroll speed to see how it works!</textarea>
|
|
| 199 |
<input type="file" id="file-input" accept=".txt,.doc,.docx" class="hidden">
|
| 200 |
<custom-footer></custom-footer>
|
| 201 |
<help-modal></help-modal>
|
| 202 |
-
|
| 203 |
<script src="components/footer.js"></script>
|
| 204 |
<script src="components/help-modal.js"></script>
|
| 205 |
<script src="script.js"></script>
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>>_teleprompter</title>
|
| 7 |
+
<link rel="stylesheet" href="style.css">
|
| 8 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
<script src="https://unpkg.com/feather-icons"></script>
|
| 10 |
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
|
|
|
| 42 |
<i data-feather="x" class="w-4 h-4"></i>
|
| 43 |
</button>
|
| 44 |
</div>
|
| 45 |
+
<h1 class="text-3xl font-bold">>_teleprompter</h1>
|
| 46 |
+
<p class="text-gray-200 mt-2">Sistema Profesional de Teleprompter</p>
|
| 47 |
</div>
|
| 48 |
+
<div class="p-6 grid grid-cols-1 lg:grid-cols-3 gap-6 relative">
|
| 49 |
<div class="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-primary-500 to-secondary-500"></div>
|
| 50 |
<div class="lg:col-span-1 space-y-6">
|
| 51 |
<div>
|
| 52 |
<label class="block text-sm font-medium text-gray-300 mb-1 flex items-center justify-between">
|
| 53 |
+
<span>Título del Script</span>
|
| 54 |
<span class="text-xs text-gray-400">Ctrl+T</span>
|
| 55 |
</label>
|
| 56 |
<div class="relative">
|
| 57 |
+
<input type="text" id="script-title" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:ring-2 focus:ring-primary-500 focus:border-primary-500 outline-none transition pr-10" placeholder="Mi Presentación">
|
| 58 |
<button class="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-white">
|
| 59 |
<i data-feather="edit-2" class="w-4 h-4"></i>
|
| 60 |
</button>
|
| 61 |
</div>
|
| 62 |
</div>
|
|
|
|
| 63 |
<div>
|
| 64 |
<label class="block text-sm font-medium text-gray-300 mb-1 flex items-center justify-between">
|
| 65 |
+
<span>Velocidad de Desplazamiento</span>
|
| 66 |
<span class="text-xs text-gray-400" id="speed-value">1.0x</span>
|
| 67 |
</label>
|
| 68 |
<input type="range" id="speed-slider" min="0.1" max="5" step="0.1" value="1" class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-primary-500">
|
| 69 |
<div class="flex justify-between text-xs text-gray-400 mt-1">
|
| 70 |
+
<span>Lento</span>
|
| 71 |
+
<span>Medio</span>
|
| 72 |
+
<span>Rápido</span>
|
| 73 |
</div>
|
| 74 |
</div>
|
|
|
|
| 75 |
<div>
|
| 76 |
+
<label class="block text-sm font-medium text-gray-300 mb-1">Tamaño del Texto</label>
|
| 77 |
<select id="text-size" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:ring-2 focus:ring-primary-500 focus:border-primary-500 outline-none transition">
|
| 78 |
+
<option value="small">Pequeño</option>
|
| 79 |
+
<option value="medium" selected>Mediano</option>
|
| 80 |
+
<option value="large">Grande</option>
|
| 81 |
+
<option value="x-large">Extra Grande</option>
|
| 82 |
</select>
|
| 83 |
</div>
|
|
|
|
| 84 |
<div>
|
| 85 |
+
<label class="block text-sm font-medium text-gray-300 mb-1">Tema</label>
|
| 86 |
<div class="grid grid-cols-3 gap-2 theme-selector">
|
| 87 |
<button class="bg-blue-500 h-10 rounded-lg theme-btn active" data-theme="blue"></button>
|
| 88 |
<button class="bg-green-500 h-10 rounded-lg theme-btn" data-theme="green"></button>
|
|
|
|
| 92 |
<button class="bg-pink-500 h-10 rounded-lg theme-btn" data-theme="pink"></button>
|
| 93 |
</div>
|
| 94 |
</div>
|
|
|
|
| 95 |
<div>
|
| 96 |
+
<label class="block text-sm font-medium text-gray-300 mb-1">Alineación del Texto</label>
|
| 97 |
<div class="grid grid-cols-3 gap-2">
|
| 98 |
<button id="align-left" class="p-2 bg-gray-700 rounded-lg hover:bg-gray-600 flex items-center justify-center">
|
| 99 |
<i data-feather="align-left" class="w-4 h-4"></i>
|
|
|
|
| 106 |
</button>
|
| 107 |
</div>
|
| 108 |
</div>
|
|
|
|
| 109 |
<div>
|
| 110 |
+
<label class="block text-sm font-medium text-gray-300 mb-1">Estilo de Fuente</label>
|
| 111 |
<div class="grid grid-cols-2 gap-2">
|
| 112 |
<button id="font-sans" class="p-2 bg-gray-700 rounded-lg hover:bg-gray-600 active">Sans Serif</button>
|
| 113 |
<button id="font-serif" class="p-2 bg-gray-700 rounded-lg hover:bg-gray-600">Serif</button>
|
| 114 |
</div>
|
| 115 |
</div>
|
| 116 |
+
</div>
|
| 117 |
|
| 118 |
<div class="lg:col-span-2 flex flex-col gap-4">
|
| 119 |
<div class="bg-gray-700 rounded-lg p-4 flex-grow relative group">
|
| 120 |
<div class="absolute top-2 right-2 flex gap-1 z-10">
|
| 121 |
+
<button id="format-bold" class="p-1 bg-gray-600 rounded hover:bg-gray-500" title="Negrita">
|
| 122 |
<i data-feather="bold" class="w-4 h-4"></i>
|
| 123 |
</button>
|
| 124 |
+
<button id="format-italic" class="p-1 bg-gray-600 rounded hover:bg-gray-500" title="Cursiva">
|
| 125 |
<i data-feather="italic" class="w-4 h-4"></i>
|
| 126 |
</button>
|
| 127 |
+
<button id="format-underline" class="p-1 bg-gray-600 rounded hover:bg-gray-500" title="Subrayado">
|
| 128 |
<i data-feather="underline" class="w-4 h-4"></i>
|
| 129 |
</button>
|
| 130 |
</div>
|
| 131 |
+
<textarea id="script-textarea" class="w-full h-64 bg-transparent resize-none outline-none text-gray-200 placeholder-gray-500" placeholder="Ingrese su script aquí...">¡Bienvenido a >_teleprompter!
|
| 132 |
|
| 133 |
+
Esta es una solución profesional de teleprompter con características avanzadas:
|
| 134 |
|
| 135 |
+
• Control de desplazamiento en tiempo real
|
| 136 |
+
• Múltiples temas y personalización
|
| 137 |
+
• Opciones de formato de texto
|
| 138 |
+
• Atajos de teclado para eficiencia
|
| 139 |
+
• Guardado y carga de scripts
|
| 140 |
|
| 141 |
+
¡Intenta ajustar la velocidad de desplazamiento para ver cómo funciona!</textarea>
|
| 142 |
<div class="absolute bottom-4 right-4 opacity-0 group-hover:opacity-100 transition flex gap-2">
|
| 143 |
+
<button id="import-script" class="p-2 bg-gray-600 rounded-lg hover:bg-gray-500" title="Importar Script">
|
| 144 |
<i data-feather="upload" class="w-4 h-4"></i>
|
| 145 |
</button>
|
| 146 |
+
<button id="clear-script" class="p-2 bg-gray-600 rounded-lg hover:bg-gray-500" title="Limpiar Todo">
|
| 147 |
<i data-feather="trash-2" class="w-4 h-4"></i>
|
| 148 |
</button>
|
| 149 |
</div>
|
| 150 |
</div>
|
|
|
|
| 151 |
<div class="bg-gray-700 rounded-lg p-4">
|
| 152 |
<div class="flex justify-between items-center mb-2">
|
| 153 |
+
<h3 class="font-medium">Vista Previa</h3>
|
| 154 |
<div class="flex gap-2">
|
| 155 |
+
<button id="toggle-preview" class="px-3 py-1 bg-gray-600 hover:bg-gray-500 rounded text-sm">Alternar Vista</button>
|
| 156 |
+
<button id="mirror-preview" class="px-3 py-1 bg-gray-600 hover:bg-gray-500 rounded text-sm">Espejo</button>
|
| 157 |
</div>
|
| 158 |
</div>
|
| 159 |
<div id="preview-container" class="bg-black rounded p-4 h-40 overflow-hidden relative">
|
| 160 |
<div id="preview-text" class="text-white text-center text-lg leading-relaxed">
|
| 161 |
+
¡Bienvenido a >_teleprompter! Esta es una solución profesional de teleprompter con características avanzadas.
|
| 162 |
</div>
|
| 163 |
</div>
|
| 164 |
</div>
|
| 165 |
+
</div>
|
| 166 |
</div>
|
| 167 |
|
| 168 |
<div class="p-6 bg-gray-700 border-t border-gray-600 flex flex-wrap justify-between gap-4">
|
| 169 |
<div class="flex gap-2">
|
| 170 |
<button id="save-script" class="px-4 py-2 bg-gray-600 hover:bg-gray-500 rounded-lg font-medium transition flex items-center gap-2 text-sm">
|
| 171 |
+
<i data-feather="save" class="w-4 h-4"></i> Guardar
|
| 172 |
</button>
|
| 173 |
<button id="load-script" class="px-4 py-2 bg-gray-600 hover:bg-gray-500 rounded-lg font-medium transition flex items-center gap-2 text-sm">
|
| 174 |
+
<i data-feather="folder" class="w-4 h-4"></i> Cargar
|
| 175 |
</button>
|
| 176 |
<button id="export-script" class="px-4 py-2 bg-gray-600 hover:bg-gray-500 rounded-lg font-medium transition flex items-center gap-2 text-sm">
|
| 177 |
+
<i data-feather="download" class="w-4 h-4"></i> Exportar
|
| 178 |
</button>
|
| 179 |
</div>
|
| 180 |
<div class="flex gap-2">
|
| 181 |
<button id="help-btn" class="px-4 py-2 bg-gray-600 hover:bg-gray-500 rounded-lg font-medium transition flex items-center gap-2 text-sm">
|
| 182 |
+
<i data-feather="help-circle" class="w-4 h-4"></i> Ayuda
|
| 183 |
</button>
|
| 184 |
<button id="start-scroll" class="px-6 py-2 bg-primary-500 hover:bg-primary-600 rounded-lg font-medium transition flex items-center gap-2 text-sm glow">
|
| 185 |
+
<i data-feather="play" class="w-4 h-4"></i> Iniciar Desplazamiento
|
| 186 |
</button>
|
| 187 |
</div>
|
| 188 |
+
</div>
|
| 189 |
</div>
|
| 190 |
</main>
|
| 191 |
|
|
|
|
| 193 |
<input type="file" id="file-input" accept=".txt,.doc,.docx" class="hidden">
|
| 194 |
<custom-footer></custom-footer>
|
| 195 |
<help-modal></help-modal>
|
| 196 |
+
<script src="components/navbar.js"></script>
|
| 197 |
<script src="components/footer.js"></script>
|
| 198 |
<script src="components/help-modal.js"></script>
|
| 199 |
<script src="script.js"></script>
|
script.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
|
| 2 |
-
//
|
| 3 |
let isScrolling = false;
|
| 4 |
let scrollInterval;
|
| 5 |
let currentSpeed = 1;
|
|
@@ -9,7 +9,7 @@ let currentAlignment = 'center';
|
|
| 9 |
let currentFont = 'sans';
|
| 10 |
let mirroredView = false;
|
| 11 |
|
| 12 |
-
//
|
| 13 |
const elements = {
|
| 14 |
speedSlider: document.getElementById('speed-slider'),
|
| 15 |
speedValue: document.getElementById('speed-value'),
|
|
@@ -20,46 +20,44 @@ const elements = {
|
|
| 20 |
scriptTitle: document.getElementById('script-title'),
|
| 21 |
fileInput: document.getElementById('file-input')
|
| 22 |
};
|
| 23 |
-
|
| 24 |
-
// Initialize all components
|
| 25 |
function initializeComponents() {
|
| 26 |
setupEventListeners();
|
| 27 |
loadSettings();
|
| 28 |
updatePreview();
|
| 29 |
setupKeyboardShortcuts();
|
| 30 |
}
|
| 31 |
-
|
| 32 |
-
// Set up event listeners
|
| 33 |
function setupEventListeners() {
|
| 34 |
-
//
|
| 35 |
elements.speedSlider.addEventListener('input', handleSpeedChange);
|
| 36 |
|
| 37 |
-
//
|
| 38 |
elements.scriptTextarea.addEventListener('input', updatePreview);
|
| 39 |
|
| 40 |
-
//
|
| 41 |
elements.textSizeSelect.addEventListener('change', handleTextSizeChange);
|
| 42 |
|
| 43 |
-
//
|
| 44 |
document.querySelectorAll('.theme-btn').forEach(button => {
|
| 45 |
button.addEventListener('click', () => handleThemeChange(button.dataset.theme));
|
| 46 |
});
|
| 47 |
|
| 48 |
-
//
|
| 49 |
document.getElementById('align-left').addEventListener('click', () => handleAlignmentChange('left'));
|
| 50 |
document.getElementById('align-center').addEventListener('click', () => handleAlignmentChange('center'));
|
| 51 |
document.getElementById('align-right').addEventListener('click', () => handleAlignmentChange('right'));
|
| 52 |
|
| 53 |
-
//
|
| 54 |
document.getElementById('font-sans').addEventListener('click', () => handleFontChange('sans'));
|
| 55 |
document.getElementById('font-serif').addEventListener('click', () => handleFontChange('serif'));
|
| 56 |
|
| 57 |
-
//
|
| 58 |
document.getElementById('format-bold').addEventListener('click', () => toggleFormatting('bold'));
|
| 59 |
document.getElementById('format-italic').addEventListener('click', () => toggleFormatting('italic'));
|
| 60 |
document.getElementById('format-underline').addEventListener('click', () => toggleFormatting('underline'));
|
| 61 |
|
| 62 |
-
//
|
| 63 |
document.getElementById('start-scroll').addEventListener('click', toggleScrolling);
|
| 64 |
document.getElementById('save-script').addEventListener('click', saveScript);
|
| 65 |
document.getElementById('load-script').addEventListener('click', loadScript);
|
|
@@ -69,14 +67,13 @@ function setupEventListeners() {
|
|
| 69 |
document.getElementById('toggle-preview').addEventListener('click', togglePreviewMode);
|
| 70 |
document.getElementById('mirror-preview').addEventListener('click', toggleMirrorView);
|
| 71 |
|
| 72 |
-
//
|
| 73 |
elements.fileInput.addEventListener('change', importScriptFromFile);
|
| 74 |
|
| 75 |
-
//
|
| 76 |
window.addEventListener('beforeunload', saveSettings);
|
| 77 |
}
|
| 78 |
-
|
| 79 |
-
// Handle speed change
|
| 80 |
function handleSpeedChange() {
|
| 81 |
currentSpeed = parseFloat(elements.speedSlider.value);
|
| 82 |
elements.speedValue.textContent = `${currentSpeed.toFixed(1)}x`;
|
|
@@ -86,24 +83,22 @@ function handleSpeedChange() {
|
|
| 86 |
startScrolling();
|
| 87 |
}
|
| 88 |
}
|
| 89 |
-
|
| 90 |
-
// Handle text size change
|
| 91 |
function handleTextSizeChange() {
|
| 92 |
currentTextSize = elements.textSizeSelect.value;
|
| 93 |
updatePreview();
|
| 94 |
}
|
| 95 |
-
|
| 96 |
-
// Handle theme change
|
| 97 |
function handleThemeChange(theme) {
|
| 98 |
currentTheme = theme;
|
| 99 |
|
| 100 |
-
//
|
| 101 |
document.querySelectorAll('.theme-btn').forEach(btn => {
|
| 102 |
btn.classList.remove('active');
|
| 103 |
});
|
| 104 |
document.querySelector(`.theme-btn[data-theme="${theme}"]`).classList.add('active');
|
| 105 |
|
| 106 |
-
//
|
| 107 |
const themeColors = {
|
| 108 |
blue: 'from-blue-500 to-blue-700',
|
| 109 |
green: 'from-green-500 to-green-700',
|
|
@@ -118,12 +113,11 @@ function handleThemeChange(theme) {
|
|
| 118 |
|
| 119 |
updatePreview();
|
| 120 |
}
|
| 121 |
-
|
| 122 |
-
// Handle alignment change
|
| 123 |
function handleAlignmentChange(alignment) {
|
| 124 |
currentAlignment = alignment;
|
| 125 |
|
| 126 |
-
//
|
| 127 |
document.querySelectorAll('#align-left, #align-center, #align-right').forEach(btn => {
|
| 128 |
btn.classList.remove('active');
|
| 129 |
});
|
|
@@ -131,33 +125,30 @@ function handleAlignmentChange(alignment) {
|
|
| 131 |
|
| 132 |
updatePreview();
|
| 133 |
}
|
| 134 |
-
|
| 135 |
-
// Handle font change
|
| 136 |
function handleFontChange(font) {
|
| 137 |
currentFont = font;
|
| 138 |
|
| 139 |
-
//
|
| 140 |
document.getElementById('font-sans').classList.toggle('active', font === 'sans');
|
| 141 |
document.getElementById('font-serif').classList.toggle('active', font === 'serif');
|
| 142 |
|
| 143 |
updatePreview();
|
| 144 |
}
|
| 145 |
-
|
| 146 |
-
// Toggle text formatting
|
| 147 |
function toggleFormatting(format) {
|
| 148 |
const button = document.getElementById(`format-${format}`);
|
| 149 |
button.classList.toggle('active');
|
| 150 |
|
| 151 |
-
//
|
| 152 |
-
showToast(`
|
| 153 |
}
|
| 154 |
-
|
| 155 |
-
// Update preview
|
| 156 |
function updatePreview() {
|
| 157 |
-
const text = elements.scriptTextarea.value || "
|
| 158 |
elements.previewText.textContent = text;
|
| 159 |
|
| 160 |
-
//
|
| 161 |
const sizeClasses = {
|
| 162 |
small: 'text-sm',
|
| 163 |
medium: 'text-base',
|
|
@@ -167,67 +158,63 @@ function updatePreview() {
|
|
| 167 |
|
| 168 |
elements.previewText.className = sizeClasses[currentTextSize] || 'text-base';
|
| 169 |
|
| 170 |
-
//
|
| 171 |
elements.previewText.classList.remove('text-left', 'text-center', 'text-right');
|
| 172 |
elements.previewText.classList.add(`text-${currentAlignment}`);
|
| 173 |
|
| 174 |
-
//
|
| 175 |
elements.previewText.classList.toggle('font-serif', currentFont === 'serif');
|
| 176 |
|
| 177 |
-
//
|
| 178 |
elements.previewText.classList.toggle('bold', document.getElementById('format-bold').classList.contains('active'));
|
| 179 |
elements.previewText.classList.toggle('italic', document.getElementById('format-italic').classList.contains('active'));
|
| 180 |
elements.previewText.classList.toggle('underline', document.getElementById('format-underline').classList.contains('active'));
|
| 181 |
}
|
| 182 |
-
|
| 183 |
-
// Toggle scrolling
|
| 184 |
function toggleScrolling() {
|
| 185 |
const button = document.getElementById('start-scroll');
|
| 186 |
|
| 187 |
if (isScrolling) {
|
| 188 |
stopScrolling();
|
| 189 |
-
button.innerHTML = '<i data-feather="play" class="w-4 h-4"></i>
|
| 190 |
feather.replace();
|
| 191 |
} else {
|
| 192 |
startScrolling();
|
| 193 |
-
button.innerHTML = '<i data-feather="pause" class="w-4 h-4"></i>
|
| 194 |
feather.replace();
|
| 195 |
}
|
| 196 |
}
|
| 197 |
-
|
| 198 |
-
// Start scrolling animation
|
| 199 |
function startScrolling() {
|
| 200 |
isScrolling = true;
|
| 201 |
|
| 202 |
-
//
|
| 203 |
if (scrollInterval) {
|
| 204 |
clearInterval(scrollInterval);
|
| 205 |
}
|
| 206 |
|
| 207 |
-
//
|
| 208 |
-
const baseDuration = 30; //
|
| 209 |
-
const duration = (baseDuration / currentSpeed) * 1000; //
|
| 210 |
|
| 211 |
-
//
|
| 212 |
elements.previewText.style.animation = 'none';
|
| 213 |
-
void elements.previewText.offsetWidth; //
|
| 214 |
|
| 215 |
-
//
|
| 216 |
elements.previewText.style.animation = `scroll ${duration}ms linear infinite`;
|
| 217 |
|
| 218 |
-
//
|
| 219 |
elements.previewContainer.classList.add('scrolling');
|
| 220 |
}
|
| 221 |
-
|
| 222 |
-
// Stop scrolling animation
|
| 223 |
function stopScrolling() {
|
| 224 |
isScrolling = false;
|
| 225 |
clearInterval(scrollInterval);
|
| 226 |
elements.previewText.style.animation = 'none';
|
| 227 |
elements.previewContainer.classList.remove('scrolling');
|
| 228 |
}
|
| 229 |
-
|
| 230 |
-
// Save script to localStorage
|
| 231 |
function saveScript() {
|
| 232 |
const scriptData = {
|
| 233 |
title: elements.scriptTitle.value,
|
|
@@ -240,10 +227,9 @@ function saveScript() {
|
|
| 240 |
};
|
| 241 |
|
| 242 |
localStorage.setItem('teleprompterScript', JSON.stringify(scriptData));
|
| 243 |
-
showToast('Script
|
| 244 |
}
|
| 245 |
-
|
| 246 |
-
// Load script from localStorage
|
| 247 |
function loadScript() {
|
| 248 |
const savedData = localStorage.getItem('teleprompterScript');
|
| 249 |
|
|
@@ -264,13 +250,12 @@ function loadScript() {
|
|
| 264 |
handleFontChange(scriptData.font || 'sans');
|
| 265 |
|
| 266 |
updatePreview();
|
| 267 |
-
showToast('Script
|
| 268 |
} else {
|
| 269 |
-
showToast('No
|
| 270 |
}
|
| 271 |
}
|
| 272 |
-
|
| 273 |
-
// Export script as file
|
| 274 |
function exportScript() {
|
| 275 |
const content = elements.scriptTextarea.value;
|
| 276 |
const title = elements.scriptTitle.value || 'teleprompter-script';
|
|
@@ -289,10 +274,9 @@ function exportScript() {
|
|
| 289 |
URL.revokeObjectURL(url);
|
| 290 |
}, 100);
|
| 291 |
|
| 292 |
-
showToast('Script
|
| 293 |
}
|
| 294 |
-
|
| 295 |
-
// Import script from file
|
| 296 |
function importScriptFromFile(event) {
|
| 297 |
const file = event.target.files[0];
|
| 298 |
if (!file) return;
|
|
@@ -300,71 +284,67 @@ function importScriptFromFile(event) {
|
|
| 300 |
const reader = new FileReader();
|
| 301 |
reader.onload = function(e) {
|
| 302 |
elements.scriptTextarea.value = e.target.result;
|
| 303 |
-
elements.scriptTitle.value = file.name.replace(/\.[^/.]+$/, ""); //
|
| 304 |
updatePreview();
|
| 305 |
-
showToast('Script
|
| 306 |
};
|
| 307 |
reader.readAsText(file);
|
| 308 |
|
| 309 |
-
//
|
| 310 |
elements.fileInput.value = '';
|
| 311 |
}
|
| 312 |
-
|
| 313 |
-
// Clear script
|
| 314 |
function clearScript() {
|
| 315 |
-
if (confirm('
|
| 316 |
elements.scriptTextarea.value = '';
|
| 317 |
elements.scriptTitle.value = '';
|
| 318 |
updatePreview();
|
| 319 |
-
showToast('Script
|
| 320 |
}
|
| 321 |
}
|
| 322 |
-
|
| 323 |
-
// Toggle preview mode
|
| 324 |
function togglePreviewMode() {
|
| 325 |
elements.previewContainer.classList.toggle('bg-black');
|
| 326 |
elements.previewContainer.classList.toggle('bg-gray-900');
|
| 327 |
-
showToast('
|
| 328 |
}
|
| 329 |
-
|
| 330 |
-
// Toggle mirror view
|
| 331 |
function toggleMirrorView() {
|
| 332 |
mirroredView = !mirroredView;
|
| 333 |
elements.previewContainer.classList.toggle('mirror', mirroredView);
|
| 334 |
-
showToast(mirroredView ? '
|
| 335 |
}
|
| 336 |
-
|
| 337 |
-
// Setup keyboard shortcuts
|
| 338 |
function setupKeyboardShortcuts() {
|
| 339 |
document.addEventListener('keydown', function(e) {
|
| 340 |
-
//
|
| 341 |
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
| 342 |
|
| 343 |
-
//
|
| 344 |
if (e.code === 'Space') {
|
| 345 |
e.preventDefault();
|
| 346 |
toggleScrolling();
|
| 347 |
}
|
| 348 |
|
| 349 |
-
// Ctrl+S
|
| 350 |
if (e.ctrlKey && e.code === 'KeyS') {
|
| 351 |
e.preventDefault();
|
| 352 |
saveScript();
|
| 353 |
}
|
| 354 |
|
| 355 |
-
// Ctrl+O
|
| 356 |
if (e.ctrlKey && e.code === 'KeyO') {
|
| 357 |
e.preventDefault();
|
| 358 |
loadScript();
|
| 359 |
}
|
| 360 |
|
| 361 |
-
// Ctrl+E
|
| 362 |
if (e.ctrlKey && e.code === 'KeyE') {
|
| 363 |
e.preventDefault();
|
| 364 |
exportScript();
|
| 365 |
}
|
| 366 |
|
| 367 |
-
//
|
| 368 |
if (e.code === 'ArrowUp') {
|
| 369 |
e.preventDefault();
|
| 370 |
const newValue = Math.min(5, parseFloat(elements.speedSlider.value) + 0.1);
|
|
@@ -380,8 +360,7 @@ function setupKeyboardShortcuts() {
|
|
| 380 |
}
|
| 381 |
});
|
| 382 |
}
|
| 383 |
-
|
| 384 |
-
// Save settings to localStorage
|
| 385 |
function saveSettings() {
|
| 386 |
const settings = {
|
| 387 |
speed: currentSpeed,
|
|
@@ -394,8 +373,7 @@ function saveSettings() {
|
|
| 394 |
|
| 395 |
localStorage.setItem('teleprompterSettings', JSON.stringify(settings));
|
| 396 |
}
|
| 397 |
-
|
| 398 |
-
// Load settings from localStorage
|
| 399 |
function loadSettings() {
|
| 400 |
const savedSettings = localStorage.getItem('teleprompterSettings');
|
| 401 |
|
|
@@ -419,8 +397,7 @@ function loadSettings() {
|
|
| 419 |
}
|
| 420 |
}
|
| 421 |
}
|
| 422 |
-
|
| 423 |
-
// Show toast notification
|
| 424 |
function showToast(message) {
|
| 425 |
const toast = document.createElement('div');
|
| 426 |
toast.className = 'toast show';
|
|
@@ -435,6 +412,5 @@ function showToast(message) {
|
|
| 435 |
}, 300);
|
| 436 |
}, 3000);
|
| 437 |
}
|
| 438 |
-
|
| 439 |
// Initialize when DOM is loaded
|
| 440 |
document.addEventListener('DOMContentLoaded', initializeComponents);
|
|
|
|
| 1 |
|
| 2 |
+
// Variables globales
|
| 3 |
let isScrolling = false;
|
| 4 |
let scrollInterval;
|
| 5 |
let currentSpeed = 1;
|
|
|
|
| 9 |
let currentFont = 'sans';
|
| 10 |
let mirroredView = false;
|
| 11 |
|
| 12 |
+
// Elementos DOM
|
| 13 |
const elements = {
|
| 14 |
speedSlider: document.getElementById('speed-slider'),
|
| 15 |
speedValue: document.getElementById('speed-value'),
|
|
|
|
| 20 |
scriptTitle: document.getElementById('script-title'),
|
| 21 |
fileInput: document.getElementById('file-input')
|
| 22 |
};
|
| 23 |
+
// Inicializar todos los componentes
|
|
|
|
| 24 |
function initializeComponents() {
|
| 25 |
setupEventListeners();
|
| 26 |
loadSettings();
|
| 27 |
updatePreview();
|
| 28 |
setupKeyboardShortcuts();
|
| 29 |
}
|
| 30 |
+
// Configurar escuchadores de eventos
|
|
|
|
| 31 |
function setupEventListeners() {
|
| 32 |
+
// Control de velocidad
|
| 33 |
elements.speedSlider.addEventListener('input', handleSpeedChange);
|
| 34 |
|
| 35 |
+
// Cambios en el área de texto
|
| 36 |
elements.scriptTextarea.addEventListener('input', updatePreview);
|
| 37 |
|
| 38 |
+
// Cambios en tamaño de texto
|
| 39 |
elements.textSizeSelect.addEventListener('change', handleTextSizeChange);
|
| 40 |
|
| 41 |
+
// Selección de tema
|
| 42 |
document.querySelectorAll('.theme-btn').forEach(button => {
|
| 43 |
button.addEventListener('click', () => handleThemeChange(button.dataset.theme));
|
| 44 |
});
|
| 45 |
|
| 46 |
+
// Alineación de texto
|
| 47 |
document.getElementById('align-left').addEventListener('click', () => handleAlignmentChange('left'));
|
| 48 |
document.getElementById('align-center').addEventListener('click', () => handleAlignmentChange('center'));
|
| 49 |
document.getElementById('align-right').addEventListener('click', () => handleAlignmentChange('right'));
|
| 50 |
|
| 51 |
+
// Estilo de fuente
|
| 52 |
document.getElementById('font-sans').addEventListener('click', () => handleFontChange('sans'));
|
| 53 |
document.getElementById('font-serif').addEventListener('click', () => handleFontChange('serif'));
|
| 54 |
|
| 55 |
+
// Botones de formato
|
| 56 |
document.getElementById('format-bold').addEventListener('click', () => toggleFormatting('bold'));
|
| 57 |
document.getElementById('format-italic').addEventListener('click', () => toggleFormatting('italic'));
|
| 58 |
document.getElementById('format-underline').addEventListener('click', () => toggleFormatting('underline'));
|
| 59 |
|
| 60 |
+
// Botones de control
|
| 61 |
document.getElementById('start-scroll').addEventListener('click', toggleScrolling);
|
| 62 |
document.getElementById('save-script').addEventListener('click', saveScript);
|
| 63 |
document.getElementById('load-script').addEventListener('click', loadScript);
|
|
|
|
| 67 |
document.getElementById('toggle-preview').addEventListener('click', togglePreviewMode);
|
| 68 |
document.getElementById('mirror-preview').addEventListener('click', toggleMirrorView);
|
| 69 |
|
| 70 |
+
// Entrada de archivo
|
| 71 |
elements.fileInput.addEventListener('change', importScriptFromFile);
|
| 72 |
|
| 73 |
+
// Eventos de ventana
|
| 74 |
window.addEventListener('beforeunload', saveSettings);
|
| 75 |
}
|
| 76 |
+
// Manejar cambio de velocidad
|
|
|
|
| 77 |
function handleSpeedChange() {
|
| 78 |
currentSpeed = parseFloat(elements.speedSlider.value);
|
| 79 |
elements.speedValue.textContent = `${currentSpeed.toFixed(1)}x`;
|
|
|
|
| 83 |
startScrolling();
|
| 84 |
}
|
| 85 |
}
|
| 86 |
+
// Manejar cambio de tamaño de texto
|
|
|
|
| 87 |
function handleTextSizeChange() {
|
| 88 |
currentTextSize = elements.textSizeSelect.value;
|
| 89 |
updatePreview();
|
| 90 |
}
|
| 91 |
+
// Manejar cambio de tema
|
|
|
|
| 92 |
function handleThemeChange(theme) {
|
| 93 |
currentTheme = theme;
|
| 94 |
|
| 95 |
+
// Actualizar botón activo
|
| 96 |
document.querySelectorAll('.theme-btn').forEach(btn => {
|
| 97 |
btn.classList.remove('active');
|
| 98 |
});
|
| 99 |
document.querySelector(`.theme-btn[data-theme="${theme}"]`).classList.add('active');
|
| 100 |
|
| 101 |
+
// Aplicar tema a la vista previa
|
| 102 |
const themeColors = {
|
| 103 |
blue: 'from-blue-500 to-blue-700',
|
| 104 |
green: 'from-green-500 to-green-700',
|
|
|
|
| 113 |
|
| 114 |
updatePreview();
|
| 115 |
}
|
| 116 |
+
// Manejar cambio de alineación
|
|
|
|
| 117 |
function handleAlignmentChange(alignment) {
|
| 118 |
currentAlignment = alignment;
|
| 119 |
|
| 120 |
+
// Actualizar botón activo
|
| 121 |
document.querySelectorAll('#align-left, #align-center, #align-right').forEach(btn => {
|
| 122 |
btn.classList.remove('active');
|
| 123 |
});
|
|
|
|
| 125 |
|
| 126 |
updatePreview();
|
| 127 |
}
|
| 128 |
+
// Manejar cambio de fuente
|
|
|
|
| 129 |
function handleFontChange(font) {
|
| 130 |
currentFont = font;
|
| 131 |
|
| 132 |
+
// Actualizar botón activo
|
| 133 |
document.getElementById('font-sans').classList.toggle('active', font === 'sans');
|
| 134 |
document.getElementById('font-serif').classList.toggle('active', font === 'serif');
|
| 135 |
|
| 136 |
updatePreview();
|
| 137 |
}
|
| 138 |
+
// Alternar formato de texto
|
|
|
|
| 139 |
function toggleFormatting(format) {
|
| 140 |
const button = document.getElementById(`format-${format}`);
|
| 141 |
button.classList.toggle('active');
|
| 142 |
|
| 143 |
+
// En una implementación real, esto aplicaría formato al texto seleccionado
|
| 144 |
+
showToast(`Alternado formato ${format}`);
|
| 145 |
}
|
| 146 |
+
// Actualizar vista previa
|
|
|
|
| 147 |
function updatePreview() {
|
| 148 |
+
const text = elements.scriptTextarea.value || "Su script aparecerá aquí...";
|
| 149 |
elements.previewText.textContent = text;
|
| 150 |
|
| 151 |
+
// Aplicar tamaño de texto
|
| 152 |
const sizeClasses = {
|
| 153 |
small: 'text-sm',
|
| 154 |
medium: 'text-base',
|
|
|
|
| 158 |
|
| 159 |
elements.previewText.className = sizeClasses[currentTextSize] || 'text-base';
|
| 160 |
|
| 161 |
+
// Aplicar alineación
|
| 162 |
elements.previewText.classList.remove('text-left', 'text-center', 'text-right');
|
| 163 |
elements.previewText.classList.add(`text-${currentAlignment}`);
|
| 164 |
|
| 165 |
+
// Aplicar fuente
|
| 166 |
elements.previewText.classList.toggle('font-serif', currentFont === 'serif');
|
| 167 |
|
| 168 |
+
// Aplicar clases de formato
|
| 169 |
elements.previewText.classList.toggle('bold', document.getElementById('format-bold').classList.contains('active'));
|
| 170 |
elements.previewText.classList.toggle('italic', document.getElementById('format-italic').classList.contains('active'));
|
| 171 |
elements.previewText.classList.toggle('underline', document.getElementById('format-underline').classList.contains('active'));
|
| 172 |
}
|
| 173 |
+
// Alternar desplazamiento
|
|
|
|
| 174 |
function toggleScrolling() {
|
| 175 |
const button = document.getElementById('start-scroll');
|
| 176 |
|
| 177 |
if (isScrolling) {
|
| 178 |
stopScrolling();
|
| 179 |
+
button.innerHTML = '<i data-feather="play" class="w-4 h-4"></i> Iniciar Desplazamiento';
|
| 180 |
feather.replace();
|
| 181 |
} else {
|
| 182 |
startScrolling();
|
| 183 |
+
button.innerHTML = '<i data-feather="pause" class="w-4 h-4"></i> Pausar Desplazamiento';
|
| 184 |
feather.replace();
|
| 185 |
}
|
| 186 |
}
|
| 187 |
+
// Iniciar animación de desplazamiento
|
|
|
|
| 188 |
function startScrolling() {
|
| 189 |
isScrolling = true;
|
| 190 |
|
| 191 |
+
// Limpiar cualquier intervalo existente
|
| 192 |
if (scrollInterval) {
|
| 193 |
clearInterval(scrollInterval);
|
| 194 |
}
|
| 195 |
|
| 196 |
+
// Calcular duración basada en velocidad (en segundos)
|
| 197 |
+
const baseDuration = 30; // Duración base para velocidad 1x
|
| 198 |
+
const duration = (baseDuration / currentSpeed) * 1000; // Convertir a milisegundos
|
| 199 |
|
| 200 |
+
// Reiniciar animación
|
| 201 |
elements.previewText.style.animation = 'none';
|
| 202 |
+
void elements.previewText.offsetWidth; // Activar reflow
|
| 203 |
|
| 204 |
+
// Aplicar animación de desplazamiento
|
| 205 |
elements.previewText.style.animation = `scroll ${duration}ms linear infinite`;
|
| 206 |
|
| 207 |
+
// Agregar clase de desplazamiento para estilizar
|
| 208 |
elements.previewContainer.classList.add('scrolling');
|
| 209 |
}
|
| 210 |
+
// Detener animación de desplazamiento
|
|
|
|
| 211 |
function stopScrolling() {
|
| 212 |
isScrolling = false;
|
| 213 |
clearInterval(scrollInterval);
|
| 214 |
elements.previewText.style.animation = 'none';
|
| 215 |
elements.previewContainer.classList.remove('scrolling');
|
| 216 |
}
|
| 217 |
+
// Guardar script en localStorage
|
|
|
|
| 218 |
function saveScript() {
|
| 219 |
const scriptData = {
|
| 220 |
title: elements.scriptTitle.value,
|
|
|
|
| 227 |
};
|
| 228 |
|
| 229 |
localStorage.setItem('teleprompterScript', JSON.stringify(scriptData));
|
| 230 |
+
showToast('¡Script guardado exitosamente!');
|
| 231 |
}
|
| 232 |
+
// Cargar script desde localStorage
|
|
|
|
| 233 |
function loadScript() {
|
| 234 |
const savedData = localStorage.getItem('teleprompterScript');
|
| 235 |
|
|
|
|
| 250 |
handleFontChange(scriptData.font || 'sans');
|
| 251 |
|
| 252 |
updatePreview();
|
| 253 |
+
showToast('¡Script cargado exitosamente!');
|
| 254 |
} else {
|
| 255 |
+
showToast('No se encontró script guardado.');
|
| 256 |
}
|
| 257 |
}
|
| 258 |
+
// Exportar script como archivo
|
|
|
|
| 259 |
function exportScript() {
|
| 260 |
const content = elements.scriptTextarea.value;
|
| 261 |
const title = elements.scriptTitle.value || 'teleprompter-script';
|
|
|
|
| 274 |
URL.revokeObjectURL(url);
|
| 275 |
}, 100);
|
| 276 |
|
| 277 |
+
showToast('¡Script exportado exitosamente!');
|
| 278 |
}
|
| 279 |
+
// Importar script desde archivo
|
|
|
|
| 280 |
function importScriptFromFile(event) {
|
| 281 |
const file = event.target.files[0];
|
| 282 |
if (!file) return;
|
|
|
|
| 284 |
const reader = new FileReader();
|
| 285 |
reader.onload = function(e) {
|
| 286 |
elements.scriptTextarea.value = e.target.result;
|
| 287 |
+
elements.scriptTitle.value = file.name.replace(/\.[^/.]+$/, ""); // Eliminar extensión
|
| 288 |
updatePreview();
|
| 289 |
+
showToast('¡Script importado exitosamente!');
|
| 290 |
};
|
| 291 |
reader.readAsText(file);
|
| 292 |
|
| 293 |
+
// Reiniciar entrada de archivo
|
| 294 |
elements.fileInput.value = '';
|
| 295 |
}
|
| 296 |
+
// Limpiar script
|
|
|
|
| 297 |
function clearScript() {
|
| 298 |
+
if (confirm('¿Está seguro de que desea limpiar el script actual?')) {
|
| 299 |
elements.scriptTextarea.value = '';
|
| 300 |
elements.scriptTitle.value = '';
|
| 301 |
updatePreview();
|
| 302 |
+
showToast('Script limpiado.');
|
| 303 |
}
|
| 304 |
}
|
| 305 |
+
// Alternar modo de vista previa
|
|
|
|
| 306 |
function togglePreviewMode() {
|
| 307 |
elements.previewContainer.classList.toggle('bg-black');
|
| 308 |
elements.previewContainer.classList.toggle('bg-gray-900');
|
| 309 |
+
showToast('Modo de vista previa alternado.');
|
| 310 |
}
|
| 311 |
+
// Alternar vista espejo
|
|
|
|
| 312 |
function toggleMirrorView() {
|
| 313 |
mirroredView = !mirroredView;
|
| 314 |
elements.previewContainer.classList.toggle('mirror', mirroredView);
|
| 315 |
+
showToast(mirroredView ? 'Vista espejo habilitada.' : 'Vista espejo deshabilitada.');
|
| 316 |
}
|
| 317 |
+
// Configurar atajos de teclado
|
|
|
|
| 318 |
function setupKeyboardShortcuts() {
|
| 319 |
document.addEventListener('keydown', function(e) {
|
| 320 |
+
// Solo activar atajos cuando no esté en campos de entrada
|
| 321 |
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
| 322 |
|
| 323 |
+
// Barra espaciadora para alternar desplazamiento
|
| 324 |
if (e.code === 'Space') {
|
| 325 |
e.preventDefault();
|
| 326 |
toggleScrolling();
|
| 327 |
}
|
| 328 |
|
| 329 |
+
// Ctrl+S para guardar
|
| 330 |
if (e.ctrlKey && e.code === 'KeyS') {
|
| 331 |
e.preventDefault();
|
| 332 |
saveScript();
|
| 333 |
}
|
| 334 |
|
| 335 |
+
// Ctrl+O para cargar
|
| 336 |
if (e.ctrlKey && e.code === 'KeyO') {
|
| 337 |
e.preventDefault();
|
| 338 |
loadScript();
|
| 339 |
}
|
| 340 |
|
| 341 |
+
// Ctrl+E para exportar
|
| 342 |
if (e.ctrlKey && e.code === 'KeyE') {
|
| 343 |
e.preventDefault();
|
| 344 |
exportScript();
|
| 345 |
}
|
| 346 |
|
| 347 |
+
// Flechas Arriba/Abajo para ajustar velocidad
|
| 348 |
if (e.code === 'ArrowUp') {
|
| 349 |
e.preventDefault();
|
| 350 |
const newValue = Math.min(5, parseFloat(elements.speedSlider.value) + 0.1);
|
|
|
|
| 360 |
}
|
| 361 |
});
|
| 362 |
}
|
| 363 |
+
// Guardar configuraciones en localStorage
|
|
|
|
| 364 |
function saveSettings() {
|
| 365 |
const settings = {
|
| 366 |
speed: currentSpeed,
|
|
|
|
| 373 |
|
| 374 |
localStorage.setItem('teleprompterSettings', JSON.stringify(settings));
|
| 375 |
}
|
| 376 |
+
// Cargar configuraciones desde localStorage
|
|
|
|
| 377 |
function loadSettings() {
|
| 378 |
const savedSettings = localStorage.getItem('teleprompterSettings');
|
| 379 |
|
|
|
|
| 397 |
}
|
| 398 |
}
|
| 399 |
}
|
| 400 |
+
// Mostrar notificación toast
|
|
|
|
| 401 |
function showToast(message) {
|
| 402 |
const toast = document.createElement('div');
|
| 403 |
toast.className = 'toast show';
|
|
|
|
| 412 |
}, 300);
|
| 413 |
}, 3000);
|
| 414 |
}
|
|
|
|
| 415 |
// Initialize when DOM is loaded
|
| 416 |
document.addEventListener('DOMContentLoaded', initializeComponents);
|