Cómo Configurar Flask Con htmx y Tailwind CSS

En este tutorial, aprenderá a configurar Flask con htmx y Tailwind CSS . El objetivo de htmx y Tailwind es simplificar el desarrollo web moderno para que pueda diseñar y habilitar la interactividad sin abandonar la comodidad y la facilidad de HTML. También veremos cómo usar Flask-Assets para agrupar y minimizar activos estáticos en una aplicación Flask.

htmlx

htmx es una biblioteca que le permite acceder a funciones de navegador modernas como AJAX, CSS Transitions, WebSockets y Server-Sent Events directamente desde HTML, en lugar de usar JavaScript. Le permite crear interfaces de usuario rápidamente directamente en el marcado.

htmx amplía varias funciones ya integradas en el navegador, como realizar solicitudes HTTP y responder a eventos. Por ejemplo, en lugar de solo poder realizar solicitudes GET y POST a través de elementos ay form, puede usar atributos HTML para enviar solicitudes GET, POST, PUT, PATCH o DELETE en cualquier elemento HTML:

<button hx-delete="/user/1">Delete</button>

También puede actualizar partes de una página para crear una aplicación de página única (SPA): enlace CodePen

Abra la pestaña de red en las herramientas de desarrollo del navegador. Cuando se hace clic en el botón, se envía una solicitud XHR al https://v2.jokeapi.dev/joke/Any?format=txt&safe-modepunto final. Luego, la respuesta se agrega al pelemento con un idde salida.

Para obtener más ejemplos, consulte la página de ejemplos de interfaz de usuario de los documentos oficiales de htmx.

Pros y contras

Ventajas :

  1. Productividad del desarrollador : puede crear interfaces de usuario modernas sin tocar JavaScript. Para obtener más información sobre esto, consulte Una alternativa de SPA .
  2. Tiene un gran impacto: la biblioteca en sí es pequeña (~10k min.gz'd ), libre de dependencias y ampliable .

Contras :

  1. Madurez de la biblioteca: dado que la biblioteca es bastante nueva, la documentación y las implementaciones de ejemplo son escasas.
  2. Tamaño de los datos transferidos : por lo general, los marcos SPA (como React y Vue) funcionan pasando datos entre el cliente y el servidor en formato JSON. Los datos recibidos luego son procesados ​​por el cliente. htmx, por otro lado, recibe el HTML renderizado del servidor y reemplaza el elemento de destino con la respuesta. El HTML en formato renderizado suele ser más grande en términos de tamaño que una respuesta JSON.

CSS viento de cola

Tailwind CSS es un marco CSS de "utilidad primero". En lugar de enviar componentes preconstruidos (en los que se especializan marcos como Bootstrap y Bulma ), proporciona bloques de construcción en forma de clases de utilidad que permiten crear diseños y diseños de forma rápida y sencilla.

Por ejemplo, tome el siguiente HTML y CSS:

<style>
.hello {
  height: 5px;
  width: 10px;
  background: gray;
  border-width: 1px;
  border-radius: 3px;
  padding: 5px;
}
</style>

<div class="hello">Hello World</div>

Esto se puede implementar con Tailwind así:

<div class="h-1 w-2 bg-gray-600 border rounded-sm p-1">Hello World</div>

Consulte el convertidor CSS Tailwind para convertir CSS sin formato en las clases de utilidad equivalentes en Tailwind. Compara los resultados.

Pros y contras

Ventajas :

  1. Altamente personalizable : aunque Tailwind viene con clases prediseñadas, se pueden sobrescribir con el archivo tailwind.config.js .
  2. Optimización : puede configurar Tailwind para optimizar la salida de CSS cargando solo las clases que realmente se utilizan.
  3. Modo oscuro : es fácil implementar el modo oscuro , por ejemplo, <div class="bg-white dark:bg-black">.

Contras :

  1. Componentes : Tailwind no proporciona ningún componente prediseñado oficial como botones, tarjetas, barras de navegación, etc. Los componentes tienen que ser creados desde cero. Hay algunos recursos impulsados ​​por la comunidad para componentes como Tailwind CSS Components y Tailwind Toolbox , por nombrar algunos. También hay una biblioteca de componentes poderosa, aunque paga, de los creadores de Tailwind llamada Tailwind UI .
  2. CSS está en línea : esto combina contenido y diseño, lo que aumenta el tamaño de la página y desordena el HTML.

Flask-Activos

Flask-Assets es una extensión diseñada para administrar activos estáticos en una aplicación Flask. Con él, crea una canalización de activos simple para:

  1. Compilación de hojas de estilo Sass y LESS a CSS
  2. Combinar y minimizar varios archivos CSS y JavaScript en un solo archivo para cada uno
  3. Creación de paquetes de activos para usar en sus plantillas

Con eso, ¡veamos cómo trabajar con cada una de las herramientas anteriores en Flask!

Configuración del proyecto

Para comenzar, cree un nuevo directorio para nuestro proyecto, cree y active un nuevo entorno virtual e instale Flask junto con Flask-Assets:

$ mkdir flask-htmx-tailwind && cd flask-htmx-tailwind
$ python3.10 -m venv venv
$ source venv/bin/activate
(venv)$

(venv)$ pip install Flask==2.1.1 Flask-Assets==2.0

A continuación, instalemos pytailwindcss y descarguemos su binario:

(venv)$ pip install pytailwindcss==0.1.4
(venv)$ tailwindcss

A continuación, agregue un archivo app.py :

# app.py

from flask import Flask
from flask_assets import Bundle, Environment

app = Flask(__name__)

assets = Environment(app)
css = Bundle("src/main.css", output="dist/main.css")

assets.register("css", css)
css.build()

Después de importar Bundle y Environment , creamos un nuevo Environmenty registramos nuestros activos CSS a través de un archivo Bundle.

El paquete que creamos toma src/main.css como entrada, que luego se procesará y enviará a dist/main.css cuando ejecutemos Tailwind CSS CLI.

Dado que todos los archivos estáticos de Flask residen en la carpeta "estática" de forma predeterminada, las carpetas "src" y "dist" mencionadas anteriormente residen en la carpeta "estática".

Con eso, configuremos Tailwind.

Comience creando un archivo de configuración de Tailwind:

(venv)$ tailwindcss init

Este comando creó un archivo tailwind.config.js en la raíz de su proyecto. Todas las personalizaciones relacionadas con Tailwind van a este archivo.

Actualice tailwind.config.js así:

module.exports = {
  content: [
    './templates/**/*.html',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Toma nota de la sección de contenido . Aquí configura las rutas a las plantillas HTML de su proyecto. Tailwind CSS escaneará sus plantillas, buscando nombres de clases de Tailwind. El archivo CSS de salida generado solo contendrá CSS para los nombres de clase relevantes que se encuentran en sus archivos de plantilla. Esto ayuda a mantener pequeños los archivos CSS generados, ya que solo contendrán los estilos que realmente se están utilizando.

Agrega lo siguiente a static/src/main.css :

/* static/src/main.css */

@tailwind base;
@tailwind components;
@tailwind utilities;

Aquí, definimos todas las clases base, componentsy utilitiesde Tailwind CSS.

Ahora tiene Flask-Assets y Tailwind conectados. A continuación, veremos cómo publicar un archivo index.html para ver el CSS en acción.

Ejemplo sencillo

Agregue una ruta junto con un bloque principal para ejecutar el servidor de desarrollo de Flask en app.py de la siguiente manera:

# app.py

from flask import Flask, render_template
from flask_assets import Bundle, Environment

app = Flask(__name__)

assets = Environment(app)
css = Bundle("src/main.css", output="dist/main.css")

assets.register("css", css)
css.build()


@app.route("/")
def homepage():
    return render_template("index.html")


if __name__ == "__main__":
    app.run(debug=True)

Cree una carpeta de "plantillas". Luego, agregue un archivo base.html :

<!-- templates/base.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    {% assets 'css' %}
      <link rel="stylesheet" href="{{ ASSET_URL }}">
    {% endassets %}

    <title>Flask + htmlx + Tailwind CSS</title>
  </head>
  <body class="bg-blue-100">
    {% block content %}
    {% endblock content %}
  </body>
</html>

Toma nota del {% assets 'css' %}bloque. Dado que registramos el paquete CSS con el entorno de la aplicación, podemos acceder a él usando el nombre registrado css, y {{ ASSET_URL }}automáticamente usará la ruta.

Además, agregamos algo de color al cuerpo HTML a través bg-blue-100de , que cambia el color de fondo a azul claro.

Agregue el archivo index.html :

<!-- templates/index.html -->

{% extends "base.html" %}

{% block content %}
<h1>Hello World</h1>
{% endblock content %}

Ahora, ejecute el siguiente comando en la raíz del proyecto para escanear las plantillas en busca de clases y generar un archivo CSS:

(venv)$ tailwindcss -i ./static/src/main.css -o ./static/dist/main.css --minify

Debería ver un nuevo directorio llamado "dist" dentro de la carpeta "estática".

Tome nota del archivo static/dist/main.css generado .

Inicie el servidor de desarrollo a través python app.pyde y navegue hasta http://localhost:5000 en su navegador para ver los resultados.

Con Tailwind configurado, agreguemos htmx a la mezcla y construyamos una búsqueda en vivo que muestre los resultados a medida que escribe.

Ejemplo de búsqueda en vivo

En lugar de obtener la biblioteca htmx de un CDN, descárguemosla y usemos Flask-Assets para agruparla.

Descargue la biblioteca de https://unpkg.com/htmx.org@1.7.0/dist/htmx.js y guárdela en "static/src".

Ahora, para crear un nuevo paquete para nuestros archivos JavaScript, actualice app.py así:

# app.py

from flask import Flask, render_template
from flask_assets import Bundle, Environment

app = Flask(__name__)

assets = Environment(app)
css = Bundle("src/main.css", output="dist/main.css")
js = Bundle("src/*.js", output="dist/main.js") # new

assets.register("css", css)
assets.register("js", js) # new
css.build()
js.build() # new


@app.route("/")
def homepage():
    return render_template("index.html")


if __name__ == "__main__":
    app.run(debug=True)

Aquí, creamos un nuevo paquete llamado js, que sale a static/dist/main.js . Como no estamos usando ningún filtro aquí, los archivos de origen y de destino serán los mismos.

A continuación, agregue el nuevo activo a nuestro archivo base.html :

<!-- templates/base.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    {% assets 'css' %}
      <link rel="stylesheet" href="{{ ASSET_URL }}">
    {% endassets %}

    <!-- new -->
    {% assets 'js' %}
      <script type="text/javascript" src="{{ ASSET_URL }}"></script>
    {% endassets %}

    <title>Flask + htmlx + Tailwind CSS</title>
  </head>
  <body class="bg-blue-100">
    {% block content %}
    {% endblock content %}
  </body>
</html>

Para que tengamos algunos datos con los que trabajar, guarde https://github.com/testdrivenio/flask-htmx-tailwind/blob/master/todo.py en un nuevo archivo llamado todo.py.

Agregaremos la capacidad de buscar según el título de cada tarea pendiente.

Actualice el archivo index.html así:

<!-- templates/index.html -->

{% extends 'base.html' %}

{% block content %}
<div class="w-small w-2/3 mx-auto py-10 text-gray-600">
  <input
    type="text"
    name="search"
    hx-post="/search"
    hx-trigger="keyup changed delay:250ms"
    hx-indicator=".htmx-indicator"
    hx-target="#todo-results"
    placeholder="Search"
    class="bg-white h-10 px-5 pr-10 rounded-full text-2xl focus:outline-none"
  >
  <span class="htmx-indicator">Searching...</span>
</div>

<table class="border-collapse w-small w-2/3 mx-auto">
  <thead>
    <tr>
      <th class="p-3 font-bold uppercase bg-gray-200 text-gray-600 border border-gray-300 hidden lg:table-cell">#</th>
      <th class="p-3 font-bold uppercase bg-gray-200 text-gray-600 border border-gray-300 hidden lg:table-cell">Title</th>
      <th class="p-3 font-bold uppercase bg-gray-200 text-gray-600 border border-gray-300 hidden lg:table-cell">Completed</th>
    </tr>
  </thead>
  <tbody id="todo-results">
    {% include 'todo.html' %}
  </tbody>
</table>
{% endblock content %}

Tomemos un momento para ver los atributos definidos desde htmx:

<input
  type="text"
  name="search"
  hx-post="/search"
  hx-trigger="keyup changed delay:250ms"
  hx-indicator=".htmx-indicator"
  hx-target="#todo-results"
  placeholder="Search"
  class="bg-white h-10 px-5 pr-10 rounded-full text-2xl focus:outline-none"
>
  1. La entrada envía una solicitud POST al /searchpunto final.
  2. La solicitud se activa a través de un evento keyup con un retraso de 250 ms. Por lo tanto, si se ingresa un nuevo evento de activación antes de que hayan transcurrido 250 ms después de la última activación, la solicitud no se activa.
  3. La respuesta HTML de la solicitud se muestra en el #todo-resultselemento.
  4. También tenemos un indicador, un elemento de carga que aparece después de que se envía la solicitud y desaparece después de que regresa la respuesta.

Agrega el archivo templates/todo.html :

<!-- templates/todo.html -->

{% if todos|length>0 %}
  {% for todo in todos %}
    <tr class="bg-white lg:hover:bg-gray-100 flex lg:table-row flex-row lg:flex-row flex-wrap lg:flex-no-wrap mb-10 lg:mb-0">
      <td class="w-full lg:w-auto p-3 text-gray-800 text-center border border-b block lg:table-cell relative lg:static">{{todo.id}}</td>
      <td class="w-full lg:w-auto p-3 text-gray-800 text-center border border-b block lg:table-cell relative lg:static">{{todo.title}}</td>
      <td class="w-full lg:w-auto p-3 text-gray-800 text-center border border-b block lg:table-cell relative lg:static">
        {% if todo.completed %}
          <span class="rounded bg-green-400 py-1 px-3 text-xs font-bold">Yes</span>
        {% else %}
          <span class="rounded bg-red-400 py-1 px-3 text-xs font-bold">No</span>
        {% endif %}
      </td>
    </tr>
  {% endfor %}
{% endif %}

Este archivo muestra todos los que coinciden con nuestra consulta de búsqueda.

Finalmente, agregue el controlador de ruta a app.py :

@app.route("/search", methods=["POST"])
def search_todo():
    search_term = request.form.get("search")

    if not len(search_term):
        return render_template("todo.html", todos=[])

    res_todos = []
    for todo in todos:
        if search_term in todo["title"]:
            res_todos.append(todo)

    return render_template("todo.html", todos=res_todos)

El /searchpunto final busca todos y presenta la plantilla todo.html con todos los resultados.

Actualice las importaciones en la parte superior:

from flask import Flask, render_template, request
from flask_assets import Bundle, Environment

from todo import todos

A continuación, actualice el archivo CSS de salida:

(venv)$ tailwindcss -i ./static/src/main.css -o ./static/dist/main.css --minify

Ejecute la aplicación usando python app.pyy navegue hasta http://localhost:5000 nuevamente para probarla:

manifestación

Conclusión

En este tutorial, vimos cómo:

  • Configurar Flask-Assets, htmx y Tailwind CSS
  • Cree una aplicación de búsqueda en vivo usando Flask, Tailwind CSS y htmx

htmx puede representar elementos sin recargar la página. Lo más importante es que puede lograr esto sin escribir JavaScript. Aunque esto reduce la cantidad de trabajo requerido en el lado del cliente, los datos enviados desde el servidor pueden ser más altos ya que está enviando HTML renderizado.

Ofrecer plantillas HTML parciales como esta fue popular a principios de la década de 2000. htmx proporciona un giro moderno a este enfoque. En general, ofrecer plantillas parciales se está volviendo popular nuevamente debido a la complejidad de los marcos como React y Vue. Puede agregar WebSockets a la mezcla para ofrecer cambios en tiempo real también. Este mismo enfoque es utilizado por el famoso Phoenix LiveView . Puede leer más sobre HTML sobre WebSockets en El futuro del software web es HTML sobre WebSockets y HTML sobre WebSockets .

La biblioteca aún es joven, pero el futuro parece muy prometedor.

Fuente:  https://testdriven.io

#flask #htmx #tailwindcss 

What is GEEK

Buddha Community

Cómo Configurar Flask Con htmx y Tailwind CSS

Cómo Configurar Flask Con htmx y Tailwind CSS

En este tutorial, aprenderá a configurar Flask con htmx y Tailwind CSS . El objetivo de htmx y Tailwind es simplificar el desarrollo web moderno para que pueda diseñar y habilitar la interactividad sin abandonar la comodidad y la facilidad de HTML. También veremos cómo usar Flask-Assets para agrupar y minimizar activos estáticos en una aplicación Flask.

htmlx

htmx es una biblioteca que le permite acceder a funciones de navegador modernas como AJAX, CSS Transitions, WebSockets y Server-Sent Events directamente desde HTML, en lugar de usar JavaScript. Le permite crear interfaces de usuario rápidamente directamente en el marcado.

htmx amplía varias funciones ya integradas en el navegador, como realizar solicitudes HTTP y responder a eventos. Por ejemplo, en lugar de solo poder realizar solicitudes GET y POST a través de elementos ay form, puede usar atributos HTML para enviar solicitudes GET, POST, PUT, PATCH o DELETE en cualquier elemento HTML:

<button hx-delete="/user/1">Delete</button>

También puede actualizar partes de una página para crear una aplicación de página única (SPA): enlace CodePen

Abra la pestaña de red en las herramientas de desarrollo del navegador. Cuando se hace clic en el botón, se envía una solicitud XHR al https://v2.jokeapi.dev/joke/Any?format=txt&safe-modepunto final. Luego, la respuesta se agrega al pelemento con un idde salida.

Para obtener más ejemplos, consulte la página de ejemplos de interfaz de usuario de los documentos oficiales de htmx.

Pros y contras

Ventajas :

  1. Productividad del desarrollador : puede crear interfaces de usuario modernas sin tocar JavaScript. Para obtener más información sobre esto, consulte Una alternativa de SPA .
  2. Tiene un gran impacto: la biblioteca en sí es pequeña (~10k min.gz'd ), libre de dependencias y ampliable .

Contras :

  1. Madurez de la biblioteca: dado que la biblioteca es bastante nueva, la documentación y las implementaciones de ejemplo son escasas.
  2. Tamaño de los datos transferidos : por lo general, los marcos SPA (como React y Vue) funcionan pasando datos entre el cliente y el servidor en formato JSON. Los datos recibidos luego son procesados ​​por el cliente. htmx, por otro lado, recibe el HTML renderizado del servidor y reemplaza el elemento de destino con la respuesta. El HTML en formato renderizado suele ser más grande en términos de tamaño que una respuesta JSON.

CSS viento de cola

Tailwind CSS es un marco CSS de "utilidad primero". En lugar de enviar componentes preconstruidos (en los que se especializan marcos como Bootstrap y Bulma ), proporciona bloques de construcción en forma de clases de utilidad que permiten crear diseños y diseños de forma rápida y sencilla.

Por ejemplo, tome el siguiente HTML y CSS:

<style>
.hello {
  height: 5px;
  width: 10px;
  background: gray;
  border-width: 1px;
  border-radius: 3px;
  padding: 5px;
}
</style>

<div class="hello">Hello World</div>

Esto se puede implementar con Tailwind así:

<div class="h-1 w-2 bg-gray-600 border rounded-sm p-1">Hello World</div>

Consulte el convertidor CSS Tailwind para convertir CSS sin formato en las clases de utilidad equivalentes en Tailwind. Compara los resultados.

Pros y contras

Ventajas :

  1. Altamente personalizable : aunque Tailwind viene con clases prediseñadas, se pueden sobrescribir con el archivo tailwind.config.js .
  2. Optimización : puede configurar Tailwind para optimizar la salida de CSS cargando solo las clases que realmente se utilizan.
  3. Modo oscuro : es fácil implementar el modo oscuro , por ejemplo, <div class="bg-white dark:bg-black">.

Contras :

  1. Componentes : Tailwind no proporciona ningún componente prediseñado oficial como botones, tarjetas, barras de navegación, etc. Los componentes tienen que ser creados desde cero. Hay algunos recursos impulsados ​​por la comunidad para componentes como Tailwind CSS Components y Tailwind Toolbox , por nombrar algunos. También hay una biblioteca de componentes poderosa, aunque paga, de los creadores de Tailwind llamada Tailwind UI .
  2. CSS está en línea : esto combina contenido y diseño, lo que aumenta el tamaño de la página y desordena el HTML.

Flask-Activos

Flask-Assets es una extensión diseñada para administrar activos estáticos en una aplicación Flask. Con él, crea una canalización de activos simple para:

  1. Compilación de hojas de estilo Sass y LESS a CSS
  2. Combinar y minimizar varios archivos CSS y JavaScript en un solo archivo para cada uno
  3. Creación de paquetes de activos para usar en sus plantillas

Con eso, ¡veamos cómo trabajar con cada una de las herramientas anteriores en Flask!

Configuración del proyecto

Para comenzar, cree un nuevo directorio para nuestro proyecto, cree y active un nuevo entorno virtual e instale Flask junto con Flask-Assets:

$ mkdir flask-htmx-tailwind && cd flask-htmx-tailwind
$ python3.10 -m venv venv
$ source venv/bin/activate
(venv)$

(venv)$ pip install Flask==2.1.1 Flask-Assets==2.0

A continuación, instalemos pytailwindcss y descarguemos su binario:

(venv)$ pip install pytailwindcss==0.1.4
(venv)$ tailwindcss

A continuación, agregue un archivo app.py :

# app.py

from flask import Flask
from flask_assets import Bundle, Environment

app = Flask(__name__)

assets = Environment(app)
css = Bundle("src/main.css", output="dist/main.css")

assets.register("css", css)
css.build()

Después de importar Bundle y Environment , creamos un nuevo Environmenty registramos nuestros activos CSS a través de un archivo Bundle.

El paquete que creamos toma src/main.css como entrada, que luego se procesará y enviará a dist/main.css cuando ejecutemos Tailwind CSS CLI.

Dado que todos los archivos estáticos de Flask residen en la carpeta "estática" de forma predeterminada, las carpetas "src" y "dist" mencionadas anteriormente residen en la carpeta "estática".

Con eso, configuremos Tailwind.

Comience creando un archivo de configuración de Tailwind:

(venv)$ tailwindcss init

Este comando creó un archivo tailwind.config.js en la raíz de su proyecto. Todas las personalizaciones relacionadas con Tailwind van a este archivo.

Actualice tailwind.config.js así:

module.exports = {
  content: [
    './templates/**/*.html',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Toma nota de la sección de contenido . Aquí configura las rutas a las plantillas HTML de su proyecto. Tailwind CSS escaneará sus plantillas, buscando nombres de clases de Tailwind. El archivo CSS de salida generado solo contendrá CSS para los nombres de clase relevantes que se encuentran en sus archivos de plantilla. Esto ayuda a mantener pequeños los archivos CSS generados, ya que solo contendrán los estilos que realmente se están utilizando.

Agrega lo siguiente a static/src/main.css :

/* static/src/main.css */

@tailwind base;
@tailwind components;
@tailwind utilities;

Aquí, definimos todas las clases base, componentsy utilitiesde Tailwind CSS.

Ahora tiene Flask-Assets y Tailwind conectados. A continuación, veremos cómo publicar un archivo index.html para ver el CSS en acción.

Ejemplo sencillo

Agregue una ruta junto con un bloque principal para ejecutar el servidor de desarrollo de Flask en app.py de la siguiente manera:

# app.py

from flask import Flask, render_template
from flask_assets import Bundle, Environment

app = Flask(__name__)

assets = Environment(app)
css = Bundle("src/main.css", output="dist/main.css")

assets.register("css", css)
css.build()


@app.route("/")
def homepage():
    return render_template("index.html")


if __name__ == "__main__":
    app.run(debug=True)

Cree una carpeta de "plantillas". Luego, agregue un archivo base.html :

<!-- templates/base.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    {% assets 'css' %}
      <link rel="stylesheet" href="{{ ASSET_URL }}">
    {% endassets %}

    <title>Flask + htmlx + Tailwind CSS</title>
  </head>
  <body class="bg-blue-100">
    {% block content %}
    {% endblock content %}
  </body>
</html>

Toma nota del {% assets 'css' %}bloque. Dado que registramos el paquete CSS con el entorno de la aplicación, podemos acceder a él usando el nombre registrado css, y {{ ASSET_URL }}automáticamente usará la ruta.

Además, agregamos algo de color al cuerpo HTML a través bg-blue-100de , que cambia el color de fondo a azul claro.

Agregue el archivo index.html :

<!-- templates/index.html -->

{% extends "base.html" %}

{% block content %}
<h1>Hello World</h1>
{% endblock content %}

Ahora, ejecute el siguiente comando en la raíz del proyecto para escanear las plantillas en busca de clases y generar un archivo CSS:

(venv)$ tailwindcss -i ./static/src/main.css -o ./static/dist/main.css --minify

Debería ver un nuevo directorio llamado "dist" dentro de la carpeta "estática".

Tome nota del archivo static/dist/main.css generado .

Inicie el servidor de desarrollo a través python app.pyde y navegue hasta http://localhost:5000 en su navegador para ver los resultados.

Con Tailwind configurado, agreguemos htmx a la mezcla y construyamos una búsqueda en vivo que muestre los resultados a medida que escribe.

Ejemplo de búsqueda en vivo

En lugar de obtener la biblioteca htmx de un CDN, descárguemosla y usemos Flask-Assets para agruparla.

Descargue la biblioteca de https://unpkg.com/htmx.org@1.7.0/dist/htmx.js y guárdela en "static/src".

Ahora, para crear un nuevo paquete para nuestros archivos JavaScript, actualice app.py así:

# app.py

from flask import Flask, render_template
from flask_assets import Bundle, Environment

app = Flask(__name__)

assets = Environment(app)
css = Bundle("src/main.css", output="dist/main.css")
js = Bundle("src/*.js", output="dist/main.js") # new

assets.register("css", css)
assets.register("js", js) # new
css.build()
js.build() # new


@app.route("/")
def homepage():
    return render_template("index.html")


if __name__ == "__main__":
    app.run(debug=True)

Aquí, creamos un nuevo paquete llamado js, que sale a static/dist/main.js . Como no estamos usando ningún filtro aquí, los archivos de origen y de destino serán los mismos.

A continuación, agregue el nuevo activo a nuestro archivo base.html :

<!-- templates/base.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    {% assets 'css' %}
      <link rel="stylesheet" href="{{ ASSET_URL }}">
    {% endassets %}

    <!-- new -->
    {% assets 'js' %}
      <script type="text/javascript" src="{{ ASSET_URL }}"></script>
    {% endassets %}

    <title>Flask + htmlx + Tailwind CSS</title>
  </head>
  <body class="bg-blue-100">
    {% block content %}
    {% endblock content %}
  </body>
</html>

Para que tengamos algunos datos con los que trabajar, guarde https://github.com/testdrivenio/flask-htmx-tailwind/blob/master/todo.py en un nuevo archivo llamado todo.py.

Agregaremos la capacidad de buscar según el título de cada tarea pendiente.

Actualice el archivo index.html así:

<!-- templates/index.html -->

{% extends 'base.html' %}

{% block content %}
<div class="w-small w-2/3 mx-auto py-10 text-gray-600">
  <input
    type="text"
    name="search"
    hx-post="/search"
    hx-trigger="keyup changed delay:250ms"
    hx-indicator=".htmx-indicator"
    hx-target="#todo-results"
    placeholder="Search"
    class="bg-white h-10 px-5 pr-10 rounded-full text-2xl focus:outline-none"
  >
  <span class="htmx-indicator">Searching...</span>
</div>

<table class="border-collapse w-small w-2/3 mx-auto">
  <thead>
    <tr>
      <th class="p-3 font-bold uppercase bg-gray-200 text-gray-600 border border-gray-300 hidden lg:table-cell">#</th>
      <th class="p-3 font-bold uppercase bg-gray-200 text-gray-600 border border-gray-300 hidden lg:table-cell">Title</th>
      <th class="p-3 font-bold uppercase bg-gray-200 text-gray-600 border border-gray-300 hidden lg:table-cell">Completed</th>
    </tr>
  </thead>
  <tbody id="todo-results">
    {% include 'todo.html' %}
  </tbody>
</table>
{% endblock content %}

Tomemos un momento para ver los atributos definidos desde htmx:

<input
  type="text"
  name="search"
  hx-post="/search"
  hx-trigger="keyup changed delay:250ms"
  hx-indicator=".htmx-indicator"
  hx-target="#todo-results"
  placeholder="Search"
  class="bg-white h-10 px-5 pr-10 rounded-full text-2xl focus:outline-none"
>
  1. La entrada envía una solicitud POST al /searchpunto final.
  2. La solicitud se activa a través de un evento keyup con un retraso de 250 ms. Por lo tanto, si se ingresa un nuevo evento de activación antes de que hayan transcurrido 250 ms después de la última activación, la solicitud no se activa.
  3. La respuesta HTML de la solicitud se muestra en el #todo-resultselemento.
  4. También tenemos un indicador, un elemento de carga que aparece después de que se envía la solicitud y desaparece después de que regresa la respuesta.

Agrega el archivo templates/todo.html :

<!-- templates/todo.html -->

{% if todos|length>0 %}
  {% for todo in todos %}
    <tr class="bg-white lg:hover:bg-gray-100 flex lg:table-row flex-row lg:flex-row flex-wrap lg:flex-no-wrap mb-10 lg:mb-0">
      <td class="w-full lg:w-auto p-3 text-gray-800 text-center border border-b block lg:table-cell relative lg:static">{{todo.id}}</td>
      <td class="w-full lg:w-auto p-3 text-gray-800 text-center border border-b block lg:table-cell relative lg:static">{{todo.title}}</td>
      <td class="w-full lg:w-auto p-3 text-gray-800 text-center border border-b block lg:table-cell relative lg:static">
        {% if todo.completed %}
          <span class="rounded bg-green-400 py-1 px-3 text-xs font-bold">Yes</span>
        {% else %}
          <span class="rounded bg-red-400 py-1 px-3 text-xs font-bold">No</span>
        {% endif %}
      </td>
    </tr>
  {% endfor %}
{% endif %}

Este archivo muestra todos los que coinciden con nuestra consulta de búsqueda.

Finalmente, agregue el controlador de ruta a app.py :

@app.route("/search", methods=["POST"])
def search_todo():
    search_term = request.form.get("search")

    if not len(search_term):
        return render_template("todo.html", todos=[])

    res_todos = []
    for todo in todos:
        if search_term in todo["title"]:
            res_todos.append(todo)

    return render_template("todo.html", todos=res_todos)

El /searchpunto final busca todos y presenta la plantilla todo.html con todos los resultados.

Actualice las importaciones en la parte superior:

from flask import Flask, render_template, request
from flask_assets import Bundle, Environment

from todo import todos

A continuación, actualice el archivo CSS de salida:

(venv)$ tailwindcss -i ./static/src/main.css -o ./static/dist/main.css --minify

Ejecute la aplicación usando python app.pyy navegue hasta http://localhost:5000 nuevamente para probarla:

manifestación

Conclusión

En este tutorial, vimos cómo:

  • Configurar Flask-Assets, htmx y Tailwind CSS
  • Cree una aplicación de búsqueda en vivo usando Flask, Tailwind CSS y htmx

htmx puede representar elementos sin recargar la página. Lo más importante es que puede lograr esto sin escribir JavaScript. Aunque esto reduce la cantidad de trabajo requerido en el lado del cliente, los datos enviados desde el servidor pueden ser más altos ya que está enviando HTML renderizado.

Ofrecer plantillas HTML parciales como esta fue popular a principios de la década de 2000. htmx proporciona un giro moderno a este enfoque. En general, ofrecer plantillas parciales se está volviendo popular nuevamente debido a la complejidad de los marcos como React y Vue. Puede agregar WebSockets a la mezcla para ofrecer cambios en tiempo real también. Este mismo enfoque es utilizado por el famoso Phoenix LiveView . Puede leer más sobre HTML sobre WebSockets en El futuro del software web es HTML sobre WebSockets y HTML sobre WebSockets .

La biblioteca aún es joven, pero el futuro parece muy prometedor.

Fuente:  https://testdriven.io

#flask #htmx #tailwindcss 

Como Configurar o Flask Com htmx e Tailwind CSS

Neste tutorial, você aprenderá como configurar o Flask com htmx e Tailwind CSS . O objetivo do htmx e do Tailwind é simplificar o desenvolvimento web moderno para que você possa projetar e permitir a interatividade sem nunca deixar o conforto e a facilidade do HTML. Também veremos como usar Flask-Assets para agrupar e reduzir ativos estáticos em um aplicativo Flask.

htmx

htmx é uma biblioteca que permite acessar recursos modernos do navegador como AJAX, transições CSS, WebSockets e eventos enviados pelo servidor diretamente do HTML, em vez de usar JavaScript. Ele permite que você construa interfaces de usuário rapidamente diretamente na marcação.

htmx estende vários recursos já embutidos no navegador, como fazer solicitações HTTP e responder a eventos. Por exemplo, em vez de apenas poder fazer solicitações GET e POST por meio ade elementos e form, você pode usar atributos HTML para enviar solicitações GET, POST, PUT, PATCH ou DELETE em qualquer elemento HTML:

<button hx-delete="/user/1">Delete</button>

Você também pode atualizar partes de uma página para criar um aplicativo de página única (SPA): link CodePen

Abra a guia de rede nas ferramentas de desenvolvimento do navegador. Quando o botão é clicado, uma solicitação XHR é enviada ao https://v2.jokeapi.dev/joke/Any?format=txt&safe-modeterminal. A resposta é então anexada ao pelemento com uma idsaída.

Para obter mais exemplos, confira a página de exemplos de interface do usuário dos documentos htmx oficiais.

Prós e contras

Prós :

  1. Produtividade do desenvolvedor : você pode criar interfaces de usuário modernas sem tocar em JavaScript. Para saber mais sobre isso, confira An SPA Alternative .
  2. Um soco : A biblioteca em si é pequena (~10k min.gz'd), livre de dependências e extensível .

Contras :

  1. Maturidade da biblioteca: Como a biblioteca é bastante nova, a documentação e as implementações de exemplo são escassas.
  2. Tamanho dos dados transferidos : Normalmente, as estruturas SPA (como React e Vue) funcionam passando dados entre o cliente e o servidor no formato JSON. Os dados recebidos são então processados ​​pelo cliente. htmx, por outro lado, recebe o HTML renderizado do servidor e substitui o elemento de destino pela resposta. O HTML no formato renderizado geralmente é maior em termos de tamanho do que uma resposta JSON.

Tailwind CSS

Tailwind CSS é um framework CSS "utilitário em primeiro lugar". Em vez de enviar componentes pré-construídos (nos quais frameworks como Bootstrap e Bulma se especializam), ele fornece blocos de construção na forma de classes de utilitários que permitem criar layouts e designs de maneira rápida e fácil.

Por exemplo, pegue o seguinte HTML e CSS:

<style>
.hello {
  height: 5px;
  width: 10px;
  background: gray;
  border-width: 1px;
  border-radius: 3px;
  padding: 5px;
}
</style>

<div class="hello">Hello World</div>

Isso pode ser implementado com o Tailwind assim:

<div class="h-1 w-2 bg-gray-600 border rounded-sm p-1">Hello World</div>

Confira o CSS Tailwind Converter para converter CSS bruto nas classes de utilitário equivalentes no Tailwind. Compare os resultados.

Prós e contras

Prós :

  1. Altamente personalizável : embora o Tailwind venha com classes pré-criadas, elas podem ser substituídas usando o arquivo tailwind.config.js .
  2. Otimização : Você pode configurar o Tailwind para otimizar a saída CSS carregando apenas as classes que são realmente usadas.
  3. Modo escuro : é fácil implementar o modo escuro - por exemplo, <div class="bg-white dark:bg-black">.

Contras :

  1. Componentes : O Tailwind não fornece nenhum componente oficial pré-construído, como botões, cartões, barras de navegação e assim por diante. Os componentes devem ser criados do zero. Existem alguns recursos orientados pela comunidade para componentes como Tailwind CSS Components e Tailwind Toolbox , para citar alguns. Há também uma biblioteca de componentes poderosa, embora paga, dos criadores do Tailwind chamada Tailwind UI .
  2. CSS é inline : combina conteúdo e design, o que aumenta o tamanho da página e desordena o HTML.

Frasco-Ativos

Flask-Assets é uma extensão projetada para gerenciar ativos estáticos em um aplicativo Flask. Com ele, você cria um pipeline de ativos simples para:

  1. Compilando Sass e LESS para folhas de estilo CSS
  2. Combinando e minificando vários arquivos CSS e JavaScript em um único arquivo para cada
  3. Criando pacotes de ativos para uso em seus modelos

Com isso, vamos ver como trabalhar com cada uma das ferramentas acima no Flask!

Configuração do projeto

Para começar, crie um novo diretório para nosso projeto, crie e ative um novo ambiente virtual e instale o Flask junto com o Flask-Assets:

$ mkdir flask-htmx-tailwind && cd flask-htmx-tailwind
$ python3.10 -m venv venv
$ source venv/bin/activate
(venv)$

(venv)$ pip install Flask==2.1.1 Flask-Assets==2.0

Em seguida, vamos instalar o pytailwindcss e fazer o download do binário:

(venv)$ pip install pytailwindcss==0.1.4
(venv)$ tailwindcss

Em seguida, adicione um arquivo app.py :

# app.py

from flask import Flask
from flask_assets import Bundle, Environment

app = Flask(__name__)

assets = Environment(app)
css = Bundle("src/main.css", output="dist/main.css")

assets.register("css", css)
css.build()

Depois de importar Bundle e Environment , criamos um novo Environmente registramos nossos ativos CSS nele por meio de um arquivo Bundle.

O pacote que criamos recebe src/main.css como entrada, que será processada e enviada para dist/main.css quando executarmos a CLI do Tailwind CSS.

Como todos os arquivos estáticos do Flask residem na pasta "static" por padrão, as pastas "src" e "dist" mencionadas acima residem na pasta "static".

Com isso, vamos configurar o Tailwind.

Comece criando um arquivo de configuração do Tailwind:

(venv)$ tailwindcss init

Este comando criou um arquivo tailwind.config.js na raiz do seu projeto. Todas as personalizações relacionadas ao Tailwind vão para este arquivo.

Atualize tailwind.config.js assim:

module.exports = {
  content: [
    './templates/**/*.html',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Tome nota da seção de conteúdo . Aqui, você configura os caminhos para os modelos HTML do seu projeto. Tailwind CSS irá escanear seus templates, procurando por nomes de classes Tailwind. O arquivo CSS de saída gerado conterá apenas CSS para os nomes de classe relevantes encontrados em seus arquivos de modelo. Isso ajuda a manter os arquivos CSS gerados pequenos, pois eles conterão apenas os estilos que estão realmente sendo usados.

Adicione o seguinte a static/src/main.css :

/* static/src/main.css */

@tailwind base;
@tailwind components;
@tailwind utilities;

Aqui, definimos todas as classes base, componentse utilitiesdo Tailwind CSS.

Agora você tem Flask-Assets e Tailwind conectados. Em seguida, veremos como servir um arquivo index.html para ver o CSS em ação.

Exemplo Simples

Adicione uma rota junto com um bloco principal para executar o servidor de desenvolvimento Flask para app.py assim:

# app.py

from flask import Flask, render_template
from flask_assets import Bundle, Environment

app = Flask(__name__)

assets = Environment(app)
css = Bundle("src/main.css", output="dist/main.css")

assets.register("css", css)
css.build()


@app.route("/")
def homepage():
    return render_template("index.html")


if __name__ == "__main__":
    app.run(debug=True)

Crie uma pasta "modelos". Em seguida, adicione um arquivo base.html a ele:

<!-- templates/base.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    {% assets 'css' %}
      <link rel="stylesheet" href="{{ ASSET_URL }}">
    {% endassets %}

    <title>Flask + htmlx + Tailwind CSS</title>
  </head>
  <body class="bg-blue-100">
    {% block content %}
    {% endblock content %}
  </body>
</html>

Tome nota do {% assets 'css' %}bloco. Como registramos o pacote CSS no ambiente do aplicativo, podemos acessá-lo usando o nome registrado css, e o {{ ASSET_URL }}usará automaticamente o caminho.

Além disso, adicionamos algumas cores ao corpo do HTML via bg-blue-100, que altera a cor do plano de fundo para azul claro.

Adicione o arquivo index.html :

<!-- templates/index.html -->

{% extends "base.html" %}

{% block content %}
<h1>Hello World</h1>
{% endblock content %}

Agora, execute o seguinte comando na raiz do projeto para verificar os modelos de classes e gerar um arquivo CSS:

(venv)$ tailwindcss -i ./static/src/main.css -o ./static/dist/main.css --minify

Você deve ver um novo diretório chamado "dist" dentro da pasta "static".

Anote o arquivo static/dist/main.css gerado.

Inicie o servidor de desenvolvimento via python app.pye navegue até http://localhost:5000 em seu navegador para ver os resultados.

Com o Tailwind configurado, vamos adicionar htmx à mistura e construir uma pesquisa ao vivo que exibe os resultados conforme você digita.

Exemplo de pesquisa ao vivo

Em vez de buscar a biblioteca htmx de um CDN, vamos baixá-la e usar o Flask-Assets para agrupá-la.

Baixe a biblioteca de https://unpkg.com/htmx.org@1.7.0/dist/htmx.js e salve-a em "static/src".

Agora, para criar um novo pacote para nossos arquivos JavaScript, atualize app.py assim:

# app.py

from flask import Flask, render_template
from flask_assets import Bundle, Environment

app = Flask(__name__)

assets = Environment(app)
css = Bundle("src/main.css", output="dist/main.css")
js = Bundle("src/*.js", output="dist/main.js") # new

assets.register("css", css)
assets.register("js", js) # new
css.build()
js.build() # new


@app.route("/")
def homepage():
    return render_template("index.html")


if __name__ == "__main__":
    app.run(debug=True)

Aqui, criamos um novo pacote chamado js, que gera static/dist/main.js . Como não estamos usando nenhum filtro aqui, os arquivos de origem e destino serão os mesmos.

Em seguida, adicione o novo ativo ao nosso arquivo base.html :

<!-- templates/base.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    {% assets 'css' %}
      <link rel="stylesheet" href="{{ ASSET_URL }}">
    {% endassets %}

    <!-- new -->
    {% assets 'js' %}
      <script type="text/javascript" src="{{ ASSET_URL }}"></script>
    {% endassets %}

    <title>Flask + htmlx + Tailwind CSS</title>
  </head>
  <body class="bg-blue-100">
    {% block content %}
    {% endblock content %}
  </body>
</html>

Para que tenhamos alguns dados para trabalhar, salve https://github.com/testdrivedio/flask-htmx-tailwind/blob/master/todo.py em um novo arquivo chamado todo.py .

Adicionaremos a capacidade de pesquisar com base no título de cada tarefa.

Atualize o arquivo index.html assim:

<!-- templates/index.html -->

{% extends 'base.html' %}

{% block content %}
<div class="w-small w-2/3 mx-auto py-10 text-gray-600">
  <input
    type="text"
    name="search"
    hx-post="/search"
    hx-trigger="keyup changed delay:250ms"
    hx-indicator=".htmx-indicator"
    hx-target="#todo-results"
    placeholder="Search"
    class="bg-white h-10 px-5 pr-10 rounded-full text-2xl focus:outline-none"
  >
  <span class="htmx-indicator">Searching...</span>
</div>

<table class="border-collapse w-small w-2/3 mx-auto">
  <thead>
    <tr>
      <th class="p-3 font-bold uppercase bg-gray-200 text-gray-600 border border-gray-300 hidden lg:table-cell">#</th>
      <th class="p-3 font-bold uppercase bg-gray-200 text-gray-600 border border-gray-300 hidden lg:table-cell">Title</th>
      <th class="p-3 font-bold uppercase bg-gray-200 text-gray-600 border border-gray-300 hidden lg:table-cell">Completed</th>
    </tr>
  </thead>
  <tbody id="todo-results">
    {% include 'todo.html' %}
  </tbody>
</table>
{% endblock content %}

Vamos dar uma olhada nos atributos definidos de htmx:

<input
  type="text"
  name="search"
  hx-post="/search"
  hx-trigger="keyup changed delay:250ms"
  hx-indicator=".htmx-indicator"
  hx-target="#todo-results"
  placeholder="Search"
  class="bg-white h-10 px-5 pr-10 rounded-full text-2xl focus:outline-none"
>
  1. A entrada envia uma solicitação POST para o /searchterminal.
  2. A solicitação é acionada por meio de um evento keyup com um atraso de 250ms. Portanto, se um novo evento de keyup for inserido antes de decorridos 250ms após a última keyup, a solicitação não será acionada.
  3. A resposta HTML da solicitação é exibida no #todo-resultselemento.
  4. Também temos um indicador, um elemento de carregamento que aparece depois que a solicitação é enviada e desaparece depois que a resposta volta.

Adicione o arquivo templates/todo.html :

<!-- templates/todo.html -->

{% if todos|length>0 %}
  {% for todo in todos %}
    <tr class="bg-white lg:hover:bg-gray-100 flex lg:table-row flex-row lg:flex-row flex-wrap lg:flex-no-wrap mb-10 lg:mb-0">
      <td class="w-full lg:w-auto p-3 text-gray-800 text-center border border-b block lg:table-cell relative lg:static">{{todo.id}}</td>
      <td class="w-full lg:w-auto p-3 text-gray-800 text-center border border-b block lg:table-cell relative lg:static">{{todo.title}}</td>
      <td class="w-full lg:w-auto p-3 text-gray-800 text-center border border-b block lg:table-cell relative lg:static">
        {% if todo.completed %}
          <span class="rounded bg-green-400 py-1 px-3 text-xs font-bold">Yes</span>
        {% else %}
          <span class="rounded bg-red-400 py-1 px-3 text-xs font-bold">No</span>
        {% endif %}
      </td>
    </tr>
  {% endfor %}
{% endif %}

Este arquivo renderiza os todos que correspondem à nossa consulta de pesquisa.

Por fim, adicione o manipulador de rotas a app.py :

@app.route("/search", methods=["POST"])
def search_todo():
    search_term = request.form.get("search")

    if not len(search_term):
        return render_template("todo.html", todos=[])

    res_todos = []
    for todo in todos:
        if search_term in todo["title"]:
            res_todos.append(todo)

    return render_template("todo.html", todos=res_todos)

O /searchterminal procura todos e renderiza o modelo todo.html com todos os resultados.

Atualize as importações no topo:

from flask import Flask, render_template, request
from flask_assets import Bundle, Environment

from todo import todos

Em seguida, atualize o arquivo CSS de saída:

(venv)$ tailwindcss -i ./static/src/main.css -o ./static/dist/main.css --minify

Execute o aplicativo usando python app.pye navegue até http://localhost:5000 novamente para testá-lo:

demonstração

Conclusão

Neste tutorial, vimos como:

  • Configurar Flask-Assets, htmx e Tailwind CSS
  • Crie um aplicativo de pesquisa ao vivo usando Flask, Tailwind CSS e htmx

htmx pode renderizar elementos sem recarregar a página. Mais importante, você pode conseguir isso sem escrever nenhum JavaScript. Embora isso reduza a quantidade de trabalho necessária no lado do cliente, os dados enviados do servidor podem ser maiores, pois ele está enviando HTML renderizado.

Servir modelos HTML parciais como esse era popular no início dos anos 2000. htmx fornece um toque moderno a essa abordagem. Em geral, servir templates parciais está se tornando popular novamente devido à complexidade de frameworks como React e Vue. Você pode adicionar WebSockets à mistura para fornecer alterações em tempo real também. Essa mesma abordagem é usada pelo famoso Phoenix LiveView . Você pode ler mais sobre HTML sobre WebSockets em O futuro do software da Web é HTML sobre WebSockets e HTML sobre WebSockets .

A biblioteca ainda é jovem, mas o futuro parece muito brilhante.

Fonte:  https://testdrive.io

#flask #htmx #tailwindcss 

Hire CSS Developer

Want to develop a website or re-design using CSS Development?

We build a website and we implemented CSS successfully if you are planning to Hire CSS Developer from HourlyDeveloper.io, We can fill your Page with creative colors and attractive Designs. We provide services in Web Designing, Website Redesigning and etc.

For more details…!!
Consult with our experts:- https://bit.ly/3hUdppS

#hire css developer #css development company #css development services #css development #css developer #css

Tailwind CSS tutorial

In this tutorial I would like to introduce you to one of the fastest growing and promising CSS Frameworks at the moment, Tailwind CSS. It is different from other frameworks, such as Bootstrap, because it is built on a new way of building user interfaces using a utility-first CSS classes structure, as opposed to the OOCSS structure from other frameworks.

By the end of this guide you will be able to install, configure and build a responsive hero section (live demo) using the utility-first classes from Tailwind CSS and configure the project using the recommended PostCSS powered Tailwind configuration file for better maintainability and versatility.

Here’s the table of contents for this tutorial for Tailwind CSS:

  • Introducing Tailwind CSS
  • Adding Tailwind CSS to your project via a package manager
  • Creating the configuration file and process your CSS with Tailwind
  • Building a responsive hero section using the utility-first classes from Tailwind
  • Customize fonts, colors and add extra classes using the configuration file
  • Reduce loading time and file size by purging the unused classes from your CSS
  • Conclusion and summary

Read the full tutorial from Themesberg.

#tailwind #tailwind-css #tailwind-css-tutorial #tutorial #open-source

Popular Tailwind CSS Plugins and Extensions - Themesberg Blog

By reading this article you will browse a list of the most popular plugins and extensions for the utility-first CSS framework, Tailwind CSS. Although the default code base of the framework already covers a lot of the needs when building user interfaces, you can never get enough plugins and extensions powered by the open-source community.

One of the requirements for a plugin to appear on this list is to be open-source with no other strings attached so that the developers browsing this list can stay assured that they can use the plugin for their Tailwind CSS powered project.

Check out the list of Tailwind CSS Plugins and Extensions on Themesberg.

#tailwindcss #tailwind #tailwind-css #tailwind-css-plugins #themesberg