De la idea al código: creando algo desde cero

Lo más divertido de ser desarrollador es empezar un proyecto nuevo: decidir cómo lo vas a construir, organizar tu tiempo y llegar a ese momento tan esperado de hacer el despliegue y verlo funcionar… ¡ESTÁ VIVOOOO! 🎉 Es una sensación realmente emocionante y apasionante.
La mejor manera de aprender, avanzar y crecer es practicar. Sí, sí: practicar, practicar y practicar. Y en este post voy a mostrarte cómo crear una extensión desde cero. En mi caso, la usaré en mi navegador (Zen), que está basado en Firefox, pero el mismo principio se puede aplicar si quieres desarrollarla para Chrome.
No pretendo dar una clase de programación, sino mostrar una pequeña parte de lo que se puede lograr con la magia del código. Para seguir este post necesitas tener conocimientos básicos de programación, y si conoces JavaScript, mucho mejor.
Listo, ya tenemos todo claro, entonces… ¡comencemos!
La idea
Cambiar el UI/UX de un sitio web puede parecer abrumador si no tienes acceso al código o no eres el administrador. Pero para eso voy a crear mi extensión: para mejorar mi experiencia en un sitio web al que no puedo modificar el código directamente.
El primer paso es analizar todos los componentes del sitio y pensar cómo quiero reacomodarlos y darles estilo. Una vez que eso está claro… empieza la magia.
La página presenta una interfaz bastante básica y una experiencia de usuario limitada. A nivel estructural, se identifican los siguientes componentes:
Header
Elemento izquierdo: Logotipo.
Elemento derecho: Botón de “Entrar”.
Observación UX: El botón resulta redundante si el usuario ya está en la página de inicio de sesión.
Navbar
Sección izquierda: Menú de navegación.
Sección derecha: Botón que permite iniciar sesión o cambiar contraseña.
Observación UX: Esta acción ya está cubierta en el formulario, lo que introduce duplicidad innecesaria.
Formulario de acceso
Título: Encabezado principal de la sección.
Subtítulo: Incluye un enlace para crear una nueva cuenta.
Campos:
Correo electrónico.
Contraseña.
Opciones adicionales: Checkbox para “Recordar datos”.
Acciones: Botones para “Ingresar” y “Recuperar contraseña”.
Card informativa
Diseño: Tarjeta de fondo azul.
Contenido: Instrucciones o información adicional para el usuario.
Este desglose servirá como base para planificar los cambios de reestructuración y estilos que implementaré mediante la extensión.
Manos a la obra
Para comenzar, el primer paso es entender cómo las extensiones de Firefox interactúan con las páginas web. Las extensiones de navegador son programas pequeños que se pueden instalar para modificar o mejorar la funcionalidad del navegador.
El objetivo es modificar la interfaz de usuario (UI) de una página web. Para lograr esto, una extensión necesita inyectar su propio código (CSS, JavaScript) en la página. El "cerebro" de la extensión es el manifest.json
. Este archivo es un manifiesto que describe la extensión, le dice al navegador qué permisos necesita y qué archivos debe ejecutar en qué momento.
{
"manifest_version": 3,
"name": "Login Hospedando UI",
"version": "0.0.1",
"description": "Esta extensión cambia la IU de la página de login para el sitio hospedando.com.mx",
"content_scripts": "" // Este lo pondré mas adelante
}
Una vez creado el manifest.json
, es momento de empezar con el código que modificará la UI de la página. Para lograrlo, necesito inyectar código en ella.
Para modificar estilos, inyectaré CSS.
Para cambiar comportamientos de botones o agregar funcionalidades, inyectaré JavaScript cuando sea necesario.
Por ahora me enfocaré en el CSS y en cambiar la apariencia en primera instancia. Para ello, el primer paso será modificar content_scripts
en el manifest.json
.
{
// ... Código de arriba
"content_scripts": [
{
"matches": ["https://www.hospedando.com.mx/paneldeclientes/administracion/clientarea.php"],
"css": ["styles.css"]
}
]
}
Listo, ahora hay que crear dentro del directorio el archivo CSS que contendrá los nuevos estilos: style.css
y ahora para probar, voy a cambiar el color de fondo a negro
body {
background-color: #000000;
}
Este es el resultado hasta ahora. Parece que hay un componente con un fondo blanco que está posicionado encima del body
. Para poder modificarlo correctamente, será necesario inspeccionar la página y identificar ese elemento: su etiqueta, clases, id o cualquier otro selector que nos permita apuntar específicamente a él desde el CSS.
Una vez identificado, podré aplicar estilos que se integren con nuestra extensión y logren el cambio visual que estoy buscando.
Después de aplicar las modificaciones al CSS, el formulario de inicio de sesión ya presenta algunos cambios visibles. Por ahora he ajustado varios elementos, aunque aún me faltan pulir ciertos detalles y trabajar en la parte derecha de la interfaz para que todo luzca coherente con el nuevo diseño.
/* === LAYOUT STRUCTURE === */
:root {
--border-radius: 10px;
--border-radius-large: 2rem;
--spacing-small: 1rem;
--spacing-medium: 2rem;
--spacing-large: 4rem;
--color-gray: #808080;
--color-white: #ffffff;
--font-size-small: 12px;
--font-size-medium: 1.1rem;
--font-size-large: 1.2rem;
--font-weight-bold: 700;
}
#main-body {
height: 100%;
padding: 0 !important;
}
.container {
width: 100% !important;
height: 100% !important;
padding: 0 !important;
display: flex !important;
}
.container > .row {
height: 100%;
margin: 0 !important;
display: flex;
width: 50%;
justify-content: center;
align-items: center;
}
.main-content {
padding: 0 !important;
margin: 0 !important;
width: initial !important;
}
.logincontainer {
padding: 0 !important;
margin: 0 !important;
max-width: initial !important;
display: flex;
flex-direction: column;
align-items: center;
}
.logincontainer img {
max-width: 200px;
margin-bottom: var(--spacing-medium);
}
/* === TYPOGRAPHY === */
.header-lined h1 {
font-weight: var(--font-weight-bold) !important;
text-align: center;
border-bottom: none !important;
}
.register,
.register a {
text-align: center;
font-size: var(--font-size-large);
}
/* === FORM ELEMENTS === */
input {
border-radius: var(--border-radius) !important;
padding: var(--spacing-medium) !important;
}
#login {
width: 100% !important;
padding: var(--spacing-small) !important;
border: none;
}
.checkbox {
display: flex;
align-items: center;
justify-content: space-between;
}
.form-group {
margin-bottom: 0;
margin-top: var(--spacing-medium);
}
.forgot-password-link {
color: var(--color-gray);
font-size: var(--font-size-small);
text-decoration: none;
transition: text-decoration 0.2s ease;
}
.forgot-password-link:hover {
text-decoration: underline;
}
/* === UTILITY CLASSES === */
.hidden {
display: none !important;
}
/* === RIGHT SIDE PANEL === */
.right-container {
width: 50%;
height: 100%;
padding: var(--spacing-medium);
}
.image-container {
width: 100%;
height: 100%;
border-radius: var(--border-radius-large);
background: url("pic_right.jpeg") no-repeat center center;
background-size: cover;
display: flex;
align-items: flex-end;
justify-content: flex-end;
padding: var(--spacing-medium) var(--spacing-large);
}
/* === NAVIGATION MENU === */
.menuRight ul li a {
color: var(--color-white);
transition: text-decoration 0.2s ease;
}
.menuRight ul li a i {
display: none;
}
.menuRight ul li a:hover,
#Primary_Navbar-Home a:hover,
#Primary_Navbar-Announcements a:hover,
#Primary_Navbar-Affiliates a:hover {
background-color: transparent !important;
text-decoration: underline;
}
Puede que, al modificar solo el CSS, todavía falten algunos ajustes. Sin embargo, eso cambiará una vez que agregue el JavaScript, ya que ahí podré manipular elementos, reorganizar componentes y añadir interactividad para completar la experiencia que busco.
{
// ... Código de arriba
"content_scripts": [
{
"matches": ["https://www.hospedando.com.mx/paneldeclientes/administracion/clientarea.php"],
"css": ["styles.css"],
"js": ["script.js"]
}
]
}
class LoginUICustomizer {
constructor() {
this.config = {
logoUrl: "https://www.hospedando.com.mx/paneldeclientes/administracion/images/logo.png",
forgotPasswordUrl: "/paneldeclientes/administracion/index.php/password/reset/begin",
elementsToHide: ["#header", "#footer", "p.bg-info"],
selectors: {
loginContainer: ".logincontainer",
registerText: "p.register",
loginForm: "form.login-form",
forgotButton: "form>div[align='center']>a",
checkbox: ".checkbox",
navbar: "ul.nav.navbar-nav",
container: "#main-body>div.container",
mainMenu: "#main-menu"
}
};
}
hideElements() {
this.config.elementsToHide.forEach(selector => {
const element = this.querySelector(selector);
if (element) {
element.classList.add("hidden");
}
});
}
addLogo() {
const loginContainer = this.querySelector(this.config.selectors.loginContainer);
if (!loginContainer) return;
const logo = this.createElement("img", {
src: this.config.logoUrl,
alt: "Hospedando Logo"
});
loginContainer.prepend(logo);
}
reorganizeForm() {
const registerText = this.querySelector(this.config.selectors.registerText);
const form = this.querySelector(this.config.selectors.loginForm);
if (registerText && form) {
form.appendChild(registerText);
}
}
setupForgotPasswordLink() {
const forgotButton = this.querySelector(this.config.selectors.forgotButton);
const checkbox = this.querySelector(this.config.selectors.checkbox);
if (forgotButton) {
forgotButton.remove();
}
if (checkbox) {
const container = this.createElement("div");
const link = this.createElement("a", {
href: this.config.forgotPasswordUrl,
textContent: "¿Olvidaste tu contraseña?",
className: "forgot-password-link"
});
container.appendChild(link);
checkbox.appendChild(container);
}
}
createRightPanel() {
const navbar = this.querySelector(this.config.selectors.navbar);
const container = this.querySelector(this.config.selectors.container);
const mainMenu = this.querySelector(this.config.selectors.mainMenu);
if (!container || !navbar) return;
const rightContainer = this.createElement("div", { className: "right-container" });
const imageContainer = this.createElement("div", { className: "image-container" });
const menu = this.createElement("div", { className: "menuRight" });
menu.appendChild(navbar);
if (mainMenu) {
mainMenu.classList.add("hidden");
}
imageContainer.appendChild(menu);
rightContainer.appendChild(imageContainer);
container.appendChild(rightContainer);
}
querySelector(selector) {
return document.querySelector(selector);
}
createElement(tag, attributes = {}) {
const element = document.createElement(tag);
Object.entries(attributes).forEach(([key, value]) => {
if (key === "textContent") {
element.textContent = value;
} else {
element[key] = value;
}
});
return element;
}
initialize() {
try {
this.hideElements();
this.createRightPanel();
this.addLogo();
this.reorganizeForm();
this.setupForgotPasswordLink();
} catch (error) {
console.error("Error initializing LoginUICustomizer:", error);
}
}
}
function initializeCustomizer() {
const customizer = new LoginUICustomizer();
customizer.initialize();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initializeCustomizer);
} else {
initializeCustomizer();
}
El resultado final es increíble, ¿no? La página luce completamente diferente y todo gracias a la magia combinada de CSS y JavaScript. Un par de líneas de código bien pensadas y… voilà, ¡una nueva experiencia de usuario!
Y esto es solo una pequeña muestra de lo que puedes lograr con un poco de creatividad y código. No se trata solo de “hacer que algo se vea bonito”, sino de adaptar las herramientas que tienes a tu manera de trabajar y disfrutar el proceso.
Si tienes curiosidad, atrévete a experimentar, rompe cosas, vuelve a armarlas y crea tu propio software, aunque sea algo pequeño como esta extensión. Al final, cada proyecto es una oportunidad para aprender y crecer como desarrollador.
Happy Coding!!!