Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Niurka77/tf-app/llms.txt

Use this file to discover all available pages before exploring further.

TF-App is built without a UI framework — every interactive element is crafted from plain HTML enhanced with Tailwind CSS utility classes and driven by vanilla JavaScript. This approach keeps the bundle lean and gives you direct, predictable control over every component. The result is a consistent, branded interface that renders faithfully inside Capacitor’s WebView on Android without any framework overhead.

The showMessage Modal

The showMessage function is the primary interactive component in TF-App. It replaces the browser’s native alert() with a styled overlay modal that looks and behaves correctly inside a Capacitor WebView, where native dialogs can be inconsistent across Android versions.
function showMessage(title, message) {
  const modal = document.getElementById('messageModal');
  const modalTitle = document.getElementById('messageModalTitle');
  const modalBody = document.getElementById('messageModalBody');
  const closeButton = document.getElementById('messageModalCloseButton');

  modalTitle.textContent = title;
  modalBody.textContent = message;
  modal.classList.remove('hidden');

  closeButton.onclick = () => {
    modal.classList.add('hidden');
  };

  modal.onclick = (event) => {
    if (event.target === modal) {
      modal.classList.add('hidden');
    }
  };
}
Here is what each part does:
  • DOM targeting by ID — The function grabs four elements by their fixed IDs (messageModal, messageModalTitle, messageModalBody, messageModalCloseButton). These IDs must exist in the view’s HTML for the function to work.
  • Setting contentmodalTitle.textContent and modalBody.textContent inject the title and message strings directly into the modal without parsing any HTML, which prevents XSS issues.
  • Showing the modalmodal.classList.remove('hidden') makes the overlay visible. Tailwind’s hidden utility maps to display: none, so removing it returns the element to its default flex display.
  • Close button handlercloseButton.onclick is reassigned on every call so the correct title and message are always in scope when the user dismisses the modal.
  • Backdrop click dismissal — The modal.onclick handler checks event.target === modal. When the user clicks on the dark backdrop (the outer element itself, not its children), the modal is hidden. Clicks on the inner card do not propagate to this check.
Call showMessage() for every user-facing notification — validation errors, success confirmations, and informational messages alike. Keeping all feedback behind a single modal system ensures a consistent look and feel across the entire app.

Required HTML Structure

Every view that calls showMessage() must include the following modal markup. Place it at the bottom of <body>, just before the closing tag, so its z-50 stacking context sits above all other content.
<div id="messageModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
  <div class="bg-white rounded-xl p-6 max-w-sm w-full mx-4 shadow-lg">
    <h3 id="messageModalTitle" class="text-lg font-bold text-green-700 mb-2"></h3>
    <p id="messageModalBody" class="text-sm text-gray-700 mb-4"></p>
    <button id="messageModalCloseButton" class="w-full bg-green-700 text-white rounded-full py-2 font-bold">
      Aceptar
    </button>
  </div>
</div>
Tailwind includes the hidden utility class by default — it applies display: none to the element. No custom CSS is required. When the class is removed via classList.remove('hidden'), the element reverts to whatever display value its other classes define (in this case flex, set by the flex utility).

Form Inputs

Login fields in TF-App use a pill-shaped input pattern: a rounded-full container with an absolutely positioned Font Awesome icon flush to the left edge. The icon is decorative, but it gives each field immediate visual meaning without requiring a separate visible label.
<label class="relative block">
  <span class="absolute inset-y-0 left-4 flex items-center text-green-700">
    <i class="fas fa-user"></i>
  </span>
  <input
    class="w-full rounded-full bg-green-100 placeholder-green-400 text-green-800 pl-12 py-3 focus:outline-none"
    placeholder="Enter DNI"
    type="text"
  />
</label>
Key classes and their roles:
ClassPurpose
relative on <label>Creates a positioning context for the icon <span>
absolute inset-y-0 left-4Pins the icon vertically centered, 1rem from the left edge
rounded-fullProduces the pill shape on the input field
bg-green-100Soft green fill matching the app’s color scheme
pl-12Adds left padding so input text does not overlap the icon
focus:outline-noneRemoves the default browser focus ring for a cleaner mobile appearance
The password field follows the same pattern with fa-lock instead of fa-user and type="password".
Integration gap — form IDs are missing in dist/index.html. main.js targets id="loginForm", id="username", id="password", and id="forgotPasswordLink" to attach its event handlers, but the current dist/index.html does not set any of those IDs on its form, inputs, or forgot-password link. The login flow will not function until you add the corresponding id attributes to those elements in dist/index.html. See the Routing & Views guide for the complete list of changes required.

Wave Decorations

Every view in TF-App opens and closes with an SVG wave band rendered in the app’s green gradient. The wave creates a branded frame around the content area without requiring any image assets. The wave is controlled by four CSS classes defined in each view’s <style> block:
.wave-container-top,
.wave-container-bottom {
  position: relative;
  width: 100%;
  height: 112px;
  overflow: hidden;
  flex-shrink: 0;
}

.wave-svg {
  position: absolute;
  width: 100%;
  height: 112px;
  display: block;
  left: 0;
}

.wave-svg-top {
  top: 0;
  transform: rotate(180deg);
}

.wave-svg-bottom {
  bottom: 0;
}
  • .wave-container-top / .wave-container-bottom — Fixed-height wrappers that clip the SVG and prevent it from affecting document flow. flex-shrink: 0 ensures the wave keeps its height even when the parent is a flex column with content that fills available space.
  • .wave-svg — Absolute-positioned SVG that fills its container. preserveAspectRatio="none" on the SVG element lets it stretch to any viewport width without distortion.
  • .wave-svg-top — The top wave uses the same path as the bottom wave but is rotated 180 degrees so the curve faces downward.
The gradient itself is defined inline inside the SVG’s <defs> block using two <linearGradient> elements — see the Customization guide to learn how to change the gradient colors.

Font Icons

TF-App loads Font Awesome 5.15.3 from the jsDelivr CDN. Add this <link> in the <head> of every view:
<link
  href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
  rel="stylesheet"
/>
Icons are rendered with the <i> tag and the fas (solid) prefix class. Common icons used across the app:
Icon classUsage
fas fa-userUsername / DNI input field
fas fa-lockPassword input field
fas fa-map-marker-altProperty location indicators on the dashboard
All icons inherit the text-green-700 color from their parent <span> so they stay consistent with the green palette without needing inline styles.

Typography

TF-App uses the Montserrat typeface loaded from Google Fonts at weights 500 (medium) and 700 (bold). Load it in the <head> of every view:
<link
  href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500;700&display=swap"
  rel="stylesheet"
/>
Apply it globally in the view’s <style> block:
body {
  font-family: "Montserrat", sans-serif;
}
The display=swap parameter ensures text renders in the system fallback font while Montserrat loads, preventing an invisible-text flash on slower connections — an important consideration for mobile devices with variable network quality.

The setupCounter Export

main.js also exports a setupCounter utility that demonstrates the vanilla JS pattern for click-driven state updates. While not used in the production login flow, it serves as a reference for adding stateful interactions to any element without a framework.
export function setupCounter(element) {
  let counter = 0
  const setCounter = (count) => {
    counter = count
    element.innerHTML = `count is ${counter}`
  }
  element.addEventListener('click', () => setCounter(counter + 1))
  setCounter(0)
}
The pattern encapsulates state (counter) inside a closure, exposes a single setCounter function that both updates the internal value and re-renders the element’s text, and attaches a click listener that increments by one. Apply the same closure pattern whenever you need a self-contained stateful component — a toggle button, an expandable panel, or a quantity selector — without reaching for a framework.

Build docs developers (and LLMs) love