<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andres Avalos Gallegos</title>
    <description>The latest articles on DEV Community by Andres Avalos Gallegos (@andres_avalosgallegos_7d).</description>
    <link>https://dev.to/andres_avalosgallegos_7d</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3936964%2F952c1d46-59a5-41de-b222-051cec9b4864.png</url>
      <title>DEV Community: Andres Avalos Gallegos</title>
      <link>https://dev.to/andres_avalosgallegos_7d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andres_avalosgallegos_7d"/>
    <language>en</language>
    <item>
      <title>Construí un clon de LWN.net en un solo App.vue de 2292 líneas porque estaba enojado</title>
      <dc:creator>Andres Avalos Gallegos</dc:creator>
      <pubDate>Mon, 18 May 2026 01:58:24 +0000</pubDate>
      <link>https://dev.to/andres_avalosgallegos_7d/construi-un-clon-de-lwnnet-en-un-solo-appvue-de-2292-lineas-porque-estaba-enojado-1mkh</link>
      <guid>https://dev.to/andres_avalosgallegos_7d/construi-un-clon-de-lwnnet-en-un-solo-appvue-de-2292-lineas-porque-estaba-enojado-1mkh</guid>
      <description>&lt;h2&gt;
  
  
  El origen: pura rabia productiva
&lt;/h2&gt;

&lt;p&gt;Línea 8 de mi &lt;code&gt;App.vue&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// y si todo o casi todo en un archivo, y GPLV2 ¿POR QUE?&lt;/span&gt;
&lt;span class="c1"&gt;// por que estaba enojado con paginas con paywalls arcaicos&lt;/span&gt;
&lt;span class="c1"&gt;// (te hablo a ti -&amp;gt; lwn.net &amp;lt;-)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Así nació &lt;strong&gt;TuxTimes&lt;/strong&gt;. Sin reunión de planificación. Sin roadmap. Sin arquitectura de microservicios. Solo un desarrollador, un café, y una rabia muy específica contra &lt;a href="https://lwn.net" rel="noopener noreferrer"&gt;LWN.net&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;LWN es legendario. Sus artículos sobre el kernel Linux son insustituibles. Pero en 2025:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💸 Paywall de $35/año para leer artículos de la semana&lt;/li&gt;
&lt;li&gt;🔒 Solo los editores pueden publicar — no hay comunidad&lt;/li&gt;
&lt;li&gt;🗞️ La interfaz parece un periódico de 1994 (sin hipérbole)&lt;/li&gt;
&lt;li&gt;📱 Sin dark mode. Sin responsivo decente. Sin filtros modernos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Así que dije &lt;strong&gt;"suficiente"&lt;/strong&gt; y abrí el editor.&lt;/p&gt;


&lt;h2&gt;
  
  
  Lo que construí
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TuxTimes&lt;/strong&gt; es una plataforma de noticias sobre Linux y software libre donde cualquiera puede publicar, todo es gratis, y la interfaz no duele usarla.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://tuxtimes.web.app" rel="noopener noreferrer"&gt;tuxtimes.web.app&lt;/a&gt;&lt;/strong&gt; | *&lt;em&gt;&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;a href="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;&lt;/a&gt;
      &lt;a href="https://github.com/Qmaker-programmer" rel="noopener noreferrer"&gt;
        Qmaker-programmer
      &lt;/a&gt; / &lt;a href="https://github.com/Qmaker-programmer/tuxtimes" rel="noopener noreferrer"&gt;
        tuxtimes
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🐧 Plataforma de noticias Linux libre, gratis y sin paywalls. Construida con Vue 3 + Firebase. Nació de la rabia contra LWN.net. GPLv2.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;████████╗██╗   ██╗██╗  ██╗    ████████╗██╗███╗   ███╗███████╗███████╗
╚══██╔══╝██║   ██║╚██╗██╔╝       ██╔══╝██║████╗ ████║██╔════╝██╔════╝
   ██║   ██║   ██║ ╚███╔╝        ██║   ██║██╔████╔██║█████╗  ███████╗
   ██║   ██║   ██║ ██╔██╗        ██║   ██║██║╚██╔╝██║██╔══╝  ╚════██║
   ██║   ╚██████╔╝██╔╝ ██╗       ██║   ██║██║ ╚═╝ ██║███████╗███████║
   ╚═╝    ╚═════╝ ╚═╝  ╚═╝       ╚═╝   ╚═╝╚═╝     ╚═╝╚══════╝╚══════╝
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🐧 TuxTimes&lt;/h1&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Qmaker-programmer/tuxtimes/preview.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FQmaker-programmer%2Ftuxtimes%2FHEAD%2Fpreview.png" alt="TuxTimes Preview"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;em&gt;El lector de noticias Linux que nació de la rabia pura y el odio a los paywalls arcaicos&lt;/em&gt;&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://vuejs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2e6553c1abc9ae32eec00127020bc6028dbae8e8b3cee314cf937dcb7f11cc31/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5675652d332e782d3446433038443f7374796c653d666f722d7468652d6261646765266c6f676f3d7675652e6a73266c6f676f436f6c6f723d7768697465" alt="Vue 3"&gt;&lt;/a&gt;
&lt;a href="https://firebase.google.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/56c9edb162cca84aac16fd644fab694e3b6d07dc0fe5be1f08ed10bb5242cf5d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f46697265626173652d4669726573746f72652d4646434132383f7374796c653d666f722d7468652d6261646765266c6f676f3d6669726562617365266c6f676f436f6c6f723d626c61636b" alt="Firebase"&gt;&lt;/a&gt;
&lt;a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/91bbdb73ac89add04086d1b9f46bf8d5b7dfcfa483e51cc508a2563c72e857bd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e6369612d47504c76322d7265643f7374796c653d666f722d7468652d6261646765266c6f676f3d676e75266c6f676f436f6c6f723d7768697465" alt="GPLv2"&gt;&lt;/a&gt;
&lt;a href="https://lwn.net" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cd16248dd8c42b71e889eb1f7629bc515219f9a61355f417211748fffa4cfe37/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f416e74692d2d50617977616c6c2d4c574e2e6e65742532302546302539462539362539352d6f72616e67653f7374796c653d666f722d7468652d6261646765" alt="LWN"&gt;&lt;/a&gt;
&lt;a href="https://github.com/Qmaker-programmer/tuxtimes/." rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8d5a497474bdb8e0468073cf07b5de5a3cc7424c4f03dff0b176ed3befd7ea22/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f45737461646f2d50726f64253230636f6e253230706167696e6163692543332542336e25323061686f72612532302d627269676874677265656e3f7374796c653d666f722d7468652d6261646765" alt="Estado"&gt;&lt;/a&gt;
&lt;a href="https://github.com/Qmaker-programmer/tuxtimes/." rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a05b01b0aa10fb050b0eed48e0fc34a9c857307624991aaebc39580daf207f99/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76732532304c574e2d313925324631392532302546302539462538462538362d626c75653f7374796c653d666f722d7468652d6261646765" alt="Score"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;br&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Nació porque estaba enojado con páginas con paywalls arcaicos (te hablo a ti → lwn.net ←)"&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;— El autor, comentario en el código, línea 8&lt;/p&gt;
&lt;/blockquote&gt;
&lt;br&gt;
&lt;p&gt;🐧 &lt;strong&gt;Un pingüino rebelde · Una app de Vue · Un grito de independencia informativa&lt;/strong&gt; 🐧&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🏆 TuxTimes vs LWN.net — La Comparativa Final&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;LWN lleva desde 1998. TuxTimes lleva un fin de semana. El resultado habla solo.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;TuxTimes&lt;/th&gt;
&lt;th&gt;LWN.net&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🌑 Dark mode&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;☀️ Light mode&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚡ High Contrast (modo hacker)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;💸 Gratis para leer&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ ($35/año)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✍️ Cualquiera puede&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Qmaker-programmer/tuxtimes" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
*&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  El stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vue 3&lt;/strong&gt; Composition API — porque Options API es 2020&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firebase Auth&lt;/strong&gt; — Google OAuth sin servidores propios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firestore&lt;/strong&gt; — NoSQL que cobra por query (así aprendes a no hacer queries en bucles)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;marked&lt;/strong&gt; — Markdown → HTML, magia negra controlada&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vite&lt;/strong&gt; — porque webpack es un recuerdo doloroso&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPLv2&lt;/strong&gt; — por coherencia ideológica y enojo&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Los features que LWN no tiene
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;TuxTimes&lt;/th&gt;
&lt;th&gt;LWN.net&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dark mode&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Light mode&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚡ High Contrast (modo hacker)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gratis para leer&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ ($35/año y gratis es limitado)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cualquiera puede publicar&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Búsqueda con #tags&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;😬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paginación&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;😬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Responsive móvil&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;💀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easter egg de Windows/BSOD&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pingüino bounceando&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Score: TuxTimes 19/19 🏆 — LWN 3/19 💀&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  La parte técnica interesante
&lt;/h2&gt;
&lt;h3&gt;
  
  
  El sistema de comentarios recursivo
&lt;/h3&gt;

&lt;p&gt;El feature más dramático del proyecto. Comentarios en árbol con depth hasta 5, y un algoritmo que me tomó más tiempo del que admito:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El Algoritmo de Poda de Fantasmas™:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cuando borras un comentario que tiene respuestas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// RECOLECTOR DE BASURA EN CASCADA REVERSA&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currentParentId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentComment&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;parentId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentParentId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Si el padre ya era fantasma y no le quedó nada útil... ¡exterminado!&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;parentHasLiveChildren&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;deleteDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parentRef&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;currentParentId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Si tiene hijos vivos → &lt;strong&gt;soft delete&lt;/strong&gt;: &lt;code&gt;[Este comentario ha sido eliminado]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Si no tiene hijos → &lt;strong&gt;purga física&lt;/strong&gt; de Firestore&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cascada reversa&lt;/strong&gt;: sube por el árbol eliminando padres fantasmas vacíos&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  El enrutamiento sin router
&lt;/h3&gt;

&lt;p&gt;Sin React Router. Sin Vue Router. Solo &lt;code&gt;window.location.hash&lt;/code&gt; y orgullo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Porque en el año 2024 seguimos usando el fragmento de la URL&lt;/span&gt;
&lt;span class="c1"&gt;// como sistema de rutas. React Router llorando en un rincón.&lt;/span&gt;
&lt;span class="c1"&gt;// Ventaja: sin SSR, sin 404s, sin drama. Solo un # y listo.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HASH_VIEWS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#reciente&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#configuracion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;settings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#favoritos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;favorites&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#nuevopost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new-post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// #post-{ID} → abre ese post directamente (compartible)&lt;/span&gt;
  &lt;span class="c1"&gt;// #cualquier-otra-cosa → filtra por ese tag&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  El Easter Egg
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// EASTER EGG: si el usuario busca "windows" → BSoD de Linux.&lt;/span&gt;
&lt;span class="c1"&gt;// (si alguien reporta esto como bug, es que no entiende la cultura)&lt;/span&gt;
&lt;span class="nf"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;showWindowsEgg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;windows&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sí. Si buscas "windows" aparece una pantalla azul de la muerte de Linux. No me arrepiento.&lt;/p&gt;

&lt;h3&gt;
  
  
  Los 3 temas
&lt;/h3&gt;

&lt;p&gt;Dark, Light, y &lt;strong&gt;High Contrast&lt;/strong&gt; — inspirado en el tema de VSCodium. Azul neón sobre negro total. El usuario se siente hackeando la NASA.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"hc"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#1aabff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0078d4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"hc"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.post-card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0078d4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;#0078d4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"hc"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.post-card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;171&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;.4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Guardados en &lt;strong&gt;cookie&lt;/strong&gt;, no en Firebase. Es preferencia del navegador, no del servidor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lo que aprendí
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Un monolito no siempre es malo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Todo vive en &lt;code&gt;App.vue&lt;/code&gt;. 2292 líneas. CSS incluido. ¿Es buena arquitectura? No. ¿Funciona perfectamente? Sí. A veces la velocidad de iteración vale más que la separación de concerns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Firestore cobra por query — literalmente&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Aprendes a optimizar cuando cada &lt;code&gt;.getDocs()&lt;/code&gt; de más sale de tu bolsillo. El resultado: código que reutiliza datos locales siempre que puede.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Filtra los posts del autor desde el array LOCAL (sin query extra 💸)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authorPostsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorUid&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorUid&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. El enojo es un motor válido&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Literalmente la mejor motivación que tuve. No había cliente, no había deadline, no había dinero. Solo la rabia de que LWN no tiene dark mode en 2025 y la certeza de que yo podía hacerlo mejor.&lt;/p&gt;




&lt;h2&gt;
  
  
  El estado actual
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Auth completa (Google + Email)&lt;/li&gt;
&lt;li&gt;✅ Editor Markdown con preview en tiempo real&lt;/li&gt;
&lt;li&gt;✅ Comentarios en árbol con poda de fantasmas&lt;/li&gt;
&lt;li&gt;✅ 3 temas (dark/light/high contrast)&lt;/li&gt;
&lt;li&gt;✅ Paginación de 20 posts con sort&lt;/li&gt;
&lt;li&gt;✅ Perfiles públicos de autor&lt;/li&gt;
&lt;li&gt;✅ Sistema de favoritos&lt;/li&gt;
&lt;li&gt;✅ Responsive en 3 breakpoints&lt;/li&gt;
&lt;li&gt;✅ Easter egg de Windows&lt;/li&gt;
&lt;li&gt;⏳ Tests (el futuro nosotros lo resolverá)&lt;/li&gt;
&lt;li&gt;⏳ Paginación en Firestore (ahora es client-side — sí, lo sé)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Contribuye
&lt;/h2&gt;

&lt;p&gt;Si eres de la comunidad Linux y quieres una plataforma libre donde publicar lo que aprendes, &lt;strong&gt;TuxTimes existe para eso&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Qmaker-programmer/tuxtimes.git
&lt;span class="nb"&gt;cd &lt;/span&gt;tuxtimes
npm &lt;span class="nb"&gt;install
cp &lt;/span&gt;src/firebase.example.js src/firebase.js
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GPLv2&lt;/strong&gt;. Fork it. Mejóralo. Mándale un PR.&lt;/p&gt;

&lt;p&gt;O simplemente úsalo: &lt;strong&gt;&lt;a href="https://tuxtimes.web.app" rel="noopener noreferrer"&gt;tuxtimes.web.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Un monolito no siempre es malo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Todo vive en &lt;code&gt;App.vue&lt;/code&gt;. 2292 líneas. CSS incluido. ¿Es buena arquitectura? No. ¿Funciona perfectamente? Sí. A veces la velocidad de iteración vale más que la separación de concerns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Firestore cobra por query — literalmente&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Aprendes a optimizar cuando cada &lt;code&gt;.getDocs()&lt;/code&gt; de más sale de tu bolsillo. El resultado: código que reutiliza datos locales siempre que puede.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Filtra los posts del autor desde el array LOCAL (sin query extra 💸)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authorPostsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorUid&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorUid&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. El enojo es un motor válido&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Literalmente la mejor motivación que tuve. No había cliente, no había deadline, no había dinero. Solo la rabia de que LWN no tiene dark mode en 2025 y la certeza de que yo podía hacerlo mejor.&lt;/p&gt;




&lt;h2&gt;
  
  
  El estado actual
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Auth completa (Google + Email)&lt;/li&gt;
&lt;li&gt;✅ Editor Markdown con preview en tiempo real&lt;/li&gt;
&lt;li&gt;✅ Comentarios en árbol con poda de fantasmas&lt;/li&gt;
&lt;li&gt;✅ 3 temas (dark/light/high contrast)&lt;/li&gt;
&lt;li&gt;✅ Paginación de 20 posts con sort&lt;/li&gt;
&lt;li&gt;✅ Perfiles públicos de autor&lt;/li&gt;
&lt;li&gt;✅ Sistema de favoritos&lt;/li&gt;
&lt;li&gt;✅ Responsive en 3 breakpoints&lt;/li&gt;
&lt;li&gt;✅ Easter egg de Windows&lt;/li&gt;
&lt;li&gt;⏳ Tests (el futuro nosotros lo resolverá)&lt;/li&gt;
&lt;li&gt;⏳ Paginación en Firestore (ahora es client-side — sí, lo sé)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Contribuye
&lt;/h2&gt;

&lt;p&gt;Si eres de la comunidad Linux y quieres una plataforma libre donde publicar lo que aprendes, &lt;strong&gt;TuxTimes existe para eso&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Qmaker-programmer/tuxtimes.git
&lt;span class="nb"&gt;cd &lt;/span&gt;tuxtimes
npm &lt;span class="nb"&gt;install
cp &lt;/span&gt;src/firebase.example.js src/firebase.js
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GPLv2&lt;/strong&gt;. Fork it. Mejóralo. Mándale un PR.&lt;/p&gt;

&lt;p&gt;O simplemente úsalo: &lt;strong&gt;&lt;a href="https://tuxtimes.web.app" rel="noopener noreferrer"&gt;tuxtimes.web.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;— Qmaker (Andres / Andresuno), el único loco que hizo esto en un solo App.vue de 2292 líneas, en un fin de semana, por puracu rabia productiva&lt;/em&gt; 🫡🐧&lt;/p&gt;




&lt;p&gt;&lt;a href="https://tuxtimes.web.app" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;¡Prueba TuxTimes ahora mismo!&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Qué opinan de meter 2000 líneas en un solo archivo? ¿Es arte o es un crimen?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>vue</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
