0.1.0 boosted
This commit is contained in:
parent
126e90084e
commit
f29c40d25e
11 changed files with 181 additions and 22 deletions
|
|
@ -1,5 +1,9 @@
|
||||||
# HTMX-PATTERNS CHANGELOG
|
# HTMX-PATTERNS CHANGELOG
|
||||||
|
|
||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
* feat boosted links
|
||||||
|
|
||||||
## 0.0.4
|
## 0.0.4
|
||||||
|
|
||||||
* fix simulated load need asyncio.sleep
|
* fix simulated load need asyncio.sleep
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# SPDX-FileCopyrightText: 2024-present Waylon S. Walker <waylon@waylonwalker.com>
|
# SPDX-FileCopyrightText: 2024-present Waylon S. Walker <waylon@waylonwalker.com>
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
__version__ = "0.0.4"
|
__version__ = "0.1.0"
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ from fastapi import Depends, FastAPI, Request
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
|
|
||||||
from htmx_patterns.__about__ import __version__
|
from htmx_patterns.__about__ import __version__
|
||||||
|
from htmx_patterns.boosted.router import boosted_router
|
||||||
from htmx_patterns.config import get_config
|
from htmx_patterns.config import get_config
|
||||||
from htmx_patterns.infinite.router import infinite_router
|
from htmx_patterns.infinite.router import infinite_router
|
||||||
|
|
||||||
|
|
@ -36,10 +37,11 @@ app = FastAPI(
|
||||||
config = get_config()
|
config = get_config()
|
||||||
|
|
||||||
app.include_router(infinite_router)
|
app.include_router(infinite_router)
|
||||||
|
app.include_router(boosted_router)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def read_main(request: Request):
|
async def index(request: Request):
|
||||||
return config.templates.TemplateResponse("index.html", {"request": request})
|
return config.templates.TemplateResponse("index.html", {"request": request})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
24
htmx_patterns/boosted/models.py
Normal file
24
htmx_patterns/boosted/models.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
from datetime import date, datetime
|
||||||
|
from typing import List, Union
|
||||||
|
|
||||||
|
from faker import Faker
|
||||||
|
from polyfactory.factories.pydantic_factory import ModelFactory
|
||||||
|
from pydantic import UUID4, BaseModel
|
||||||
|
|
||||||
|
faker = Faker()
|
||||||
|
|
||||||
|
|
||||||
|
class Person(BaseModel):
|
||||||
|
id: UUID4
|
||||||
|
name: str
|
||||||
|
birthday: Union[datetime, date]
|
||||||
|
phone_number: str
|
||||||
|
|
||||||
|
|
||||||
|
class PersonFactory(ModelFactory):
|
||||||
|
name = faker.name
|
||||||
|
phone_number = faker.phone_number
|
||||||
|
__model__ = Person
|
||||||
|
|
||||||
|
|
||||||
|
# result = PersonFactory.build()
|
||||||
37
htmx_patterns/boosted/router.py
Normal file
37
htmx_patterns/boosted/router.py
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import asyncio
|
||||||
|
import time
|
||||||
|
|
||||||
|
from fastapi import APIRouter
|
||||||
|
from fastapi.requests import Request
|
||||||
|
|
||||||
|
boosted_router = APIRouter(prefix="/boosted", tags=["Shots Methods"])
|
||||||
|
|
||||||
|
from htmx_patterns.boosted.models import PersonFactory
|
||||||
|
from htmx_patterns.config import get_config
|
||||||
|
|
||||||
|
config = get_config()
|
||||||
|
|
||||||
|
|
||||||
|
@boosted_router.get("/")
|
||||||
|
@boosted_router.get("")
|
||||||
|
async def boosted(request: Request, id: int = 0):
|
||||||
|
# simulate getting a person by id
|
||||||
|
person = PersonFactory.build()
|
||||||
|
|
||||||
|
if id > 0:
|
||||||
|
prev_id = id - 1
|
||||||
|
next_id = id + 1
|
||||||
|
else:
|
||||||
|
prev_id = None
|
||||||
|
next_id = id + 1
|
||||||
|
|
||||||
|
return config.templates.TemplateResponse(
|
||||||
|
"boosted/person.html",
|
||||||
|
{
|
||||||
|
"request": request,
|
||||||
|
"person": person,
|
||||||
|
"person_id": id,
|
||||||
|
"prev_id": prev_id,
|
||||||
|
"next_id": next_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
@ -32,11 +32,6 @@ class ApiServer(BaseModel):
|
||||||
proxy_headers: bool = True
|
proxy_headers: bool = True
|
||||||
|
|
||||||
|
|
||||||
# @pass_context
|
|
||||||
# def https_url_for(context: dict, name: str, **params: Any) -> str:
|
|
||||||
# http_url = url_for_query(context, name, **params)
|
|
||||||
# return str(http_url).replace("http", "https", 1)
|
|
||||||
|
|
||||||
|
|
||||||
@pass_context
|
@pass_context
|
||||||
def url_for_query(context: dict, name: str, **params: dict) -> str:
|
def url_for_query(context: dict, name: str, **params: dict) -> str:
|
||||||
|
|
@ -71,7 +66,6 @@ def url_for_query(context: dict, name: str, **params: dict) -> str:
|
||||||
|
|
||||||
if os.environ.get("ENV") in ["dev", "qa", "prod"]:
|
if os.environ.get("ENV") in ["dev", "qa", "prod"]:
|
||||||
updated_url = updated_url.replace("http", "https", 1)
|
updated_url = updated_url.replace("http", "https", 1)
|
||||||
|
|
||||||
return updated_url
|
return updated_url
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ async def infinite(request: Request, page: int = 1, n: int = 10):
|
||||||
persons = [PersonFactory.build() for _ in range(n)]
|
persons = [PersonFactory.build() for _ in range(n)]
|
||||||
|
|
||||||
if request.state.prefers_partial:
|
if request.state.prefers_partial:
|
||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(1)
|
||||||
return config.templates.TemplateResponse(
|
return config.templates.TemplateResponse(
|
||||||
"infinite/persons_partial.html",
|
"infinite/persons_partial.html",
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -12,18 +12,34 @@
|
||||||
<link href="{{ url_for('app_css') }}" rel="stylesheet" />
|
<link href="{{ url_for('app_css') }}" rel="stylesheet" />
|
||||||
<script src="{{ url_for('htmx') }}"></script>
|
<script src="{{ url_for('htmx') }}"></script>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||||
|
{% if DEBUG %}
|
||||||
|
{{ hot_reload.script(url_for('hot-reload') ) | safe }}
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
{% set links = {
|
||||||
|
"HTMX-PATTERNS": url_for("index"),
|
||||||
|
"Boosted Links": url_for('boosted'),
|
||||||
|
"Infinite Scroll": url_for('infinite'),
|
||||||
|
} %}
|
||||||
|
|
||||||
<body
|
<body
|
||||||
class="justify-center items-center min-h-screen bg-gray-900 bg-no-repeat bg-cover bg-gradient-to-b from-pink-950/50 min-w-screen text-shadow-xl text-shadow-zinc-950">
|
class="justify-center items-center min-h-screen bg-gray-900 bg-no-repeat bg-cover bg-gradient-to-b from-pink-950/50 min-w-screen text-shadow-xl text-shadow-zinc-950">
|
||||||
<div id="grit"
|
<div id="grit"
|
||||||
class="absolute top-0 right-0 bottom-0 left-0 justify-center items-center min-w-full bg-repeat bg-cover" style="background-image: url(https://fokais.com/grit.svg), url(https://fokais.com/grit-light.svg);
|
class="absolute top-0 right-0 bottom-0 left-0 justify-center items-center min-w-full bg-repeat bg-cover"
|
||||||
pointer-events: none"></div>
|
style="background-image: url(https://fokais.com/grit.svg), url(https://fokais.com/grit-light.svg); animation: pulse 10s cubic-bezier(0.4, 0, 0.6, 1) infinite; pointer-events: none">
|
||||||
<div id="content" class="flex flex-col items-center min-h-screen min-w-screen text-white">
|
</div>
|
||||||
{% if DEBUG %}
|
<div id="content" class="flex flex-col items-center min-h-screen min-w-screen text-white border-b">
|
||||||
{{ hot_reload.script(url_for('hot-reload') ) | safe }}
|
<nav class="flex flex-row gap-8 items-center w-full p-4 bg-black border-b-4 border-gray-800">
|
||||||
{% endif %}
|
<!-- <a href="/" class="text-3xl gap-4 font-bold">HTMX PATTERNS</a> -->
|
||||||
|
<!-- <a href="/infinite" class="text-3xl font-bold text-yellow-400">INFINITE</a> -->
|
||||||
|
{% for link, url in links.items() %}
|
||||||
|
<a href="{{ url }}"
|
||||||
|
class="text-3xl font-bold uppercase {% if not loop.first %}text-yellow-400{% endif %}">{{ link
|
||||||
|
}}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</nav>
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{{ body | safe }}
|
{{ body | safe }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
61
templates/boosted/person.html
Normal file
61
templates/boosted/person.html
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}Contact - {{ person_id }} - {{ person.name }}{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<h1 id="title"
|
||||||
|
class="inline-block pb-0 mx-auto mt-8 mb-0 text-6xl font-black leading-tight leading-loose text-transparent bg-clip-text bg-gradient-to-r from-red-600 via-pink-500 to-yellow-400 ring-red-500 text-shadow-xl text-shadow-zinc-950 ring-5">
|
||||||
|
HTMX PATTERNS - BOOSTED
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p class='text-3xl font-bold mt-0 mb-16 max-w-xl text-center prose-xl'>
|
||||||
|
Contact - {{ person_id }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class='text-3xl font-bold mt-0 mb-16 max-w-2xl text-center prose-xl'>
|
||||||
|
{{ person.name }} -
|
||||||
|
{{ person.phone_number }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 class='text-3xl font-bold mt-0 max-w-xl text-center prose-xl mt-8'>
|
||||||
|
Boosted Links
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class='flex flex-row gap-4'>
|
||||||
|
{% if prev_id is not none %}
|
||||||
|
<a href="{{ url_for('boosted', id=prev_id) }}"
|
||||||
|
class="cursor-pointer bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded" hx-boost='true'>
|
||||||
|
Previous
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="pointer-events-none bg-gray-500 text-white font-bold py-2 px-4 rounded">
|
||||||
|
Previous
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<a href="{{ url_for('boosted', id=next_id) }}"
|
||||||
|
class="cursor-pointer bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded" hx-boost='true'>
|
||||||
|
Next
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class='text-3xl font-bold mt-0 max-w-xl text-center prose-xl mt-8'>
|
||||||
|
Normal Links
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class='flex flex-row gap-4'>
|
||||||
|
{% if prev_id is not none %}
|
||||||
|
<a href="{{ url_for('boosted', id=prev_id) }}"
|
||||||
|
class="cursor-pointer bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded">
|
||||||
|
Previous
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="pointer-events-none bg-gray-500 text-white font-bold py-2 px-4 rounded">
|
||||||
|
Previous
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<a href="{{ url_for('boosted', id=next_id) }}"
|
||||||
|
class="cursor-pointer bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded">
|
||||||
|
Next
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -5,17 +5,34 @@
|
||||||
HTMX PATTERNS
|
HTMX PATTERNS
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p class='mt-0 mb-16 max-w-xl text-center prose-xl'>
|
<p class='text-3xl font-bold mt-0 mb-16 max-w-xl text-center prose-xl'>
|
||||||
A collection of HTMX patterns
|
A collection of HTMX patterns
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul id="patterns" class="flex flex-col gap-4">
|
<ul id="patterns" class="grid grid-cols-3 gap-4">
|
||||||
<li>
|
{% for link, url in links.items() %}
|
||||||
<a href="{{ url_for('infinite') }}"
|
<li class='w-full'>
|
||||||
class="cursor-pointer bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded">
|
<a href="{{ url }}"
|
||||||
Infinite Scroll
|
class="cursor-pointer bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded w-full">
|
||||||
|
{{ link }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
<!-- <a href="{{ url_for('infinite') }}" -->
|
||||||
|
<!-- class="cursor-pointer bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded"> -->
|
||||||
|
<!-- Infinite Scroll -->
|
||||||
|
<!-- </a> -->
|
||||||
|
|
||||||
|
<!-- Ajaxify - https://hypermedia.systems/htmx-in-action/#_ajax_ifying_our_application -->
|
||||||
|
<!-- Using HTTP verbs -->
|
||||||
|
<!-- Validation -->
|
||||||
|
<!-- Pagination -->
|
||||||
|
<!-- Modals -->
|
||||||
|
<!-- Active Search -->
|
||||||
|
<!-- Lazy Loading -->
|
||||||
|
<!-- Inline Delete -->
|
||||||
|
<!-- Bulk Delete -->
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% block title %}Contacts List{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 id="title"
|
<h1 id="title"
|
||||||
class="inline-block pb-0 mx-auto mt-8 mb-0 text-6xl font-black leading-tight leading-loose text-transparent bg-clip-text bg-gradient-to-r from-red-600 via-pink-500 to-yellow-400 ring-red-500 text-shadow-xl text-shadow-zinc-950 ring-5">
|
class="inline-block pb-0 mx-auto mt-8 mb-0 text-6xl font-black leading-tight leading-loose text-transparent bg-clip-text bg-gradient-to-r from-red-600 via-pink-500 to-yellow-400 ring-red-500 text-shadow-xl text-shadow-zinc-950 ring-5">
|
||||||
|
|
@ -14,7 +15,10 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div id='persons-loading' class='spinner mb-24 animate-bounce'>
|
<div id='persons-loading' class='spinner mb-24 animate-bounce'>
|
||||||
loading more contacts
|
<p class='text-xl prose-xl'>loading more contacts</p>
|
||||||
|
<p class='text-xl prose-xl'>
|
||||||
|
<em class='text-red-500'>with simulated slow down</em>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue