tighten whitespace, DRY shell and buttons
This commit is contained in:
parent
0b3b1b2731
commit
a88eba7dd1
9 changed files with 439 additions and 225 deletions
|
|
@ -6,7 +6,7 @@ import htpy as h
|
|||
from htpy import Node, Renderable
|
||||
|
||||
from repub.components import (
|
||||
admin_sidebar,
|
||||
app_shell,
|
||||
header_action_link,
|
||||
inline_button,
|
||||
inline_link,
|
||||
|
|
@ -253,21 +253,14 @@ def dashboard_page_with_data(
|
|||
) -> Renderable:
|
||||
running_items = running_executions or ()
|
||||
source_items = source_feeds or ()
|
||||
return h.main(
|
||||
id="morph",
|
||||
class_="min-h-screen lg:grid lg:grid-cols-[18rem_minmax(0,1fr)]",
|
||||
)[
|
||||
admin_sidebar(
|
||||
current_path="/",
|
||||
source_count=len(source_items),
|
||||
running_count=len(running_items),
|
||||
return app_shell(
|
||||
current_path="/",
|
||||
source_count=len(source_items),
|
||||
running_count=len(running_items),
|
||||
content=(
|
||||
dashboard_header(),
|
||||
operational_snapshot(snapshot=snapshot),
|
||||
running_executions_table(running_executions=running_items),
|
||||
published_feeds_table(source_feeds=source_items),
|
||||
),
|
||||
h.div(class_="px-4 py-4 sm:px-5 lg:px-6 lg:py-5")[
|
||||
h.div(class_="mx-auto max-w-7xl space-y-5")[
|
||||
dashboard_header(),
|
||||
operational_snapshot(snapshot=snapshot),
|
||||
running_executions_table(running_executions=running_items),
|
||||
published_feeds_table(source_feeds=source_items),
|
||||
]
|
||||
],
|
||||
]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import htpy as h
|
|||
from htpy import Node, Renderable
|
||||
|
||||
from repub.components import (
|
||||
action_button,
|
||||
inline_link,
|
||||
muted_action_link,
|
||||
page_shell,
|
||||
|
|
@ -15,34 +16,6 @@ from repub.components import (
|
|||
)
|
||||
|
||||
|
||||
def _action_button(
|
||||
*,
|
||||
label: str,
|
||||
tone: str = "default",
|
||||
disabled: bool = False,
|
||||
post_path: str | None = None,
|
||||
) -> Renderable:
|
||||
classes = {
|
||||
"default": "bg-stone-100 text-slate-700 hover:bg-stone-200",
|
||||
"danger": "bg-rose-50 text-rose-700 hover:bg-rose-100",
|
||||
}
|
||||
class_name = (
|
||||
"cursor-not-allowed bg-slate-100 text-slate-400" if disabled else classes[tone]
|
||||
)
|
||||
attributes: dict[str, str] = {}
|
||||
if post_path is not None and not disabled:
|
||||
attributes["data-on:pointerdown"] = f"@post('{post_path}')"
|
||||
return h.button(
|
||||
attributes,
|
||||
type="button",
|
||||
disabled=disabled,
|
||||
class_=(
|
||||
"inline-flex items-center whitespace-nowrap rounded-full px-3 py-1.5 "
|
||||
f"text-sm font-semibold transition {class_name}"
|
||||
),
|
||||
)[label]
|
||||
|
||||
|
||||
def _text(values: Mapping[str, object], key: str) -> str:
|
||||
return str(values[key])
|
||||
|
||||
|
|
@ -62,7 +35,7 @@ def _running_row(execution: Mapping[str, object]) -> tuple[Node, ...]:
|
|||
return (
|
||||
h.div[
|
||||
h.div(class_="font-semibold text-slate-950")[_text(execution, "source")],
|
||||
h.p(class_="mt-1 font-mono text-xs text-slate-500")[
|
||||
h.p(class_="mt-0.5 font-mono text-xs text-slate-500")[
|
||||
_text(execution, "slug")
|
||||
],
|
||||
],
|
||||
|
|
@ -73,20 +46,20 @@ def _running_row(execution: Mapping[str, object]) -> tuple[Node, ...]:
|
|||
],
|
||||
h.div[
|
||||
h.p(class_="font-medium text-slate-900")[_text(execution, "started_at")],
|
||||
h.p(class_="mt-1 text-xs text-slate-500")[_text(execution, "runtime")],
|
||||
h.p(class_="mt-0.5 text-xs text-slate-500")[_text(execution, "runtime")],
|
||||
],
|
||||
status_badge(label=_text(execution, "status"), tone="running"),
|
||||
h.div(class_="min-w-56 whitespace-normal")[
|
||||
h.div(class_="max-w-xs whitespace-normal")[
|
||||
h.p(class_="font-medium text-slate-900")[_text(execution, "stats")],
|
||||
h.p(class_="mt-1 text-xs text-slate-500")[_text(execution, "worker")],
|
||||
h.p(class_="mt-0.5 text-xs text-slate-500")[_text(execution, "worker")],
|
||||
],
|
||||
h.div(class_="flex flex-nowrap items-center gap-3")[
|
||||
h.div(class_="flex flex-wrap items-center gap-2")[
|
||||
inline_link(
|
||||
href=_text(execution, "log_href"),
|
||||
label="View log",
|
||||
tone="amber",
|
||||
),
|
||||
_action_button(
|
||||
action_button(
|
||||
label=_text(execution, "cancel_label"),
|
||||
tone="danger",
|
||||
post_path=_maybe_text(execution, "cancel_post_path"),
|
||||
|
|
@ -113,7 +86,7 @@ def _queued_row(execution: Mapping[str, object]) -> tuple[Node, ...]:
|
|||
return (
|
||||
h.div[
|
||||
h.div(class_="font-semibold text-slate-950")[_text(execution, "source")],
|
||||
h.p(class_="mt-1 font-mono text-xs text-slate-500")[
|
||||
h.p(class_="mt-0.5 font-mono text-xs text-slate-500")[
|
||||
_text(execution, "slug")
|
||||
],
|
||||
],
|
||||
|
|
@ -128,13 +101,13 @@ def _queued_row(execution: Mapping[str, object]) -> tuple[Node, ...]:
|
|||
f"#{_text(execution, 'queue_position')}"
|
||||
],
|
||||
],
|
||||
_action_button(
|
||||
action_button(
|
||||
label=_text(execution, "run_label"),
|
||||
disabled=_flag(execution, "run_disabled"),
|
||||
post_path=_maybe_text(execution, "run_post_path"),
|
||||
),
|
||||
h.div(class_="flex flex-nowrap items-center gap-2")[
|
||||
_action_button(
|
||||
h.div(class_="flex flex-wrap items-center gap-2")[
|
||||
action_button(
|
||||
label="Cancel",
|
||||
tone="danger",
|
||||
post_path=_maybe_text(execution, "cancel_post_path"),
|
||||
|
|
@ -161,7 +134,7 @@ def _upcoming_row(job: Mapping[str, object]) -> tuple[Node, ...]:
|
|||
return (
|
||||
h.div[
|
||||
h.div(class_="font-semibold text-slate-950")[_text(job, "source")],
|
||||
h.p(class_="mt-1 font-mono text-xs text-slate-500")[_text(job, "slug")],
|
||||
h.p(class_="mt-0.5 font-mono text-xs text-slate-500")[_text(job, "slug")],
|
||||
],
|
||||
h.div[next_run_label,],
|
||||
h.p(class_="font-mono text-xs text-slate-600")[_text(job, "schedule")],
|
||||
|
|
@ -169,20 +142,20 @@ def _upcoming_row(job: Mapping[str, object]) -> tuple[Node, ...]:
|
|||
label=_text(job, "enabled_label"),
|
||||
tone=_text(job, "enabled_tone"),
|
||||
),
|
||||
h.p(class_="max-w-40 whitespace-normal text-sm text-slate-500")[
|
||||
h.p(class_="max-w-32 whitespace-normal text-sm text-slate-500")[
|
||||
_text(job, "run_reason")
|
||||
],
|
||||
h.div(class_="flex flex-nowrap items-center gap-2")[
|
||||
_action_button(
|
||||
h.div(class_="flex flex-wrap items-center gap-2")[
|
||||
action_button(
|
||||
label="Run now",
|
||||
disabled=_flag(job, "run_disabled"),
|
||||
post_path=_maybe_text(job, "run_post_path"),
|
||||
),
|
||||
_action_button(
|
||||
action_button(
|
||||
label=_text(job, "toggle_label"),
|
||||
post_path=_maybe_text(job, "toggle_post_path"),
|
||||
),
|
||||
_action_button(
|
||||
action_button(
|
||||
label="Delete",
|
||||
tone="danger",
|
||||
post_path=_maybe_text(job, "delete_post_path"),
|
||||
|
|
@ -209,7 +182,7 @@ def _completed_row(execution: Mapping[str, object]) -> tuple[Node, ...]:
|
|||
return (
|
||||
h.div[
|
||||
h.div(class_="font-semibold text-slate-950")[_text(execution, "source")],
|
||||
h.p(class_="mt-1 font-mono text-xs text-slate-500")[
|
||||
h.p(class_="mt-0.5 font-mono text-xs text-slate-500")[
|
||||
_text(execution, "slug")
|
||||
],
|
||||
],
|
||||
|
|
@ -220,13 +193,13 @@ def _completed_row(execution: Mapping[str, object]) -> tuple[Node, ...]:
|
|||
],
|
||||
h.div[
|
||||
ended_at_label,
|
||||
h.p(class_="mt-1 text-xs text-slate-500")[_text(execution, "summary")],
|
||||
h.p(class_="mt-0.5 text-xs text-slate-500")[_text(execution, "summary")],
|
||||
],
|
||||
status_badge(
|
||||
label=_text(execution, "status"),
|
||||
tone=_text(execution, "status_tone"),
|
||||
),
|
||||
h.div(class_="min-w-48 whitespace-normal")[
|
||||
h.div(class_="max-w-[14rem] whitespace-normal")[
|
||||
h.p(class_="font-medium text-slate-900")[_text(execution, "stats")]
|
||||
],
|
||||
inline_link(
|
||||
|
|
|
|||
|
|
@ -5,7 +5,13 @@ from collections.abc import Mapping
|
|||
import htpy as h
|
||||
from htpy import Renderable
|
||||
|
||||
from repub.components import input_field, muted_action_link, page_shell, section_card
|
||||
from repub.components import (
|
||||
action_button,
|
||||
input_field,
|
||||
muted_action_link,
|
||||
page_shell,
|
||||
section_card,
|
||||
)
|
||||
|
||||
|
||||
def _value(settings: Mapping[str, object] | None, key: str, default: str = "") -> str:
|
||||
|
|
@ -71,10 +77,12 @@ def settings_page(
|
|||
],
|
||||
h.div(class_="flex flex-wrap justify-end gap-3 pt-2")[
|
||||
muted_action_link(href="/", label="Back to dashboard"),
|
||||
h.button(
|
||||
type="submit",
|
||||
class_="rounded-full bg-slate-950 px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-slate-800",
|
||||
)["Save settings"],
|
||||
action_button(
|
||||
label="Save settings",
|
||||
tone="dark",
|
||||
emphasis="regular",
|
||||
button_type="submit",
|
||||
),
|
||||
],
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
import htpy as h
|
||||
from htpy import Node, Renderable
|
||||
|
||||
from repub.components import admin_sidebar
|
||||
from repub.components import app_shell
|
||||
|
||||
ON_LOAD_JS = (
|
||||
"@post(window.location.pathname + "
|
||||
|
|
@ -33,43 +33,34 @@ def shim_page(
|
|||
}
|
||||
),
|
||||
h.noscript["Your browser does not support JavaScript!"],
|
||||
h.main(
|
||||
id="morph",
|
||||
class_="min-h-screen lg:grid lg:grid-cols-[18rem_minmax(0,1fr)]",
|
||||
)[
|
||||
admin_sidebar(
|
||||
current_path=current_path,
|
||||
source_count=0,
|
||||
running_count=0,
|
||||
),
|
||||
h.div(class_="px-4 py-4 sm:px-5 lg:px-6 lg:py-5")[
|
||||
h.div(class_="mx-auto max-w-7xl space-y-5")[
|
||||
h.section[
|
||||
h.div(
|
||||
class_="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between"
|
||||
)[
|
||||
h.div(class_="max-w-3xl")[
|
||||
h.p(
|
||||
class_="text-xs font-semibold uppercase tracking-[0.22em] text-amber-600"
|
||||
)["Connecting"],
|
||||
h.h1(
|
||||
class_="mt-1 text-3xl font-semibold tracking-tight text-slate-950"
|
||||
)["Loading page"],
|
||||
],
|
||||
]
|
||||
],
|
||||
h.section(
|
||||
class_="overflow-hidden rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"
|
||||
app_shell(
|
||||
current_path=current_path,
|
||||
content=(
|
||||
h.section[
|
||||
h.div(
|
||||
class_="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between"
|
||||
)[
|
||||
h.div(class_="animate-pulse space-y-4 p-6")[
|
||||
h.div(class_="h-5 w-40 rounded-full bg-stone-100"),
|
||||
h.div(class_="h-12 rounded-2xl bg-stone-100"),
|
||||
h.div(class_="h-12 rounded-2xl bg-stone-100"),
|
||||
h.div(class_="h-12 rounded-2xl bg-stone-100"),
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
h.div(class_="max-w-3xl")[
|
||||
h.p(
|
||||
class_="text-xs font-semibold uppercase tracking-[0.22em] text-amber-600"
|
||||
)["Connecting"],
|
||||
h.h1(
|
||||
class_="mt-1 text-3xl font-semibold tracking-tight text-slate-950"
|
||||
)["Loading page"],
|
||||
],
|
||||
]
|
||||
],
|
||||
h.section(
|
||||
class_="overflow-hidden rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"
|
||||
)[
|
||||
h.div(class_="animate-pulse space-y-4 p-6")[
|
||||
h.div(class_="h-5 w-40 rounded-full bg-stone-100"),
|
||||
h.div(class_="h-12 rounded-2xl bg-stone-100"),
|
||||
h.div(class_="h-12 rounded-2xl bg-stone-100"),
|
||||
h.div(class_="h-12 rounded-2xl bg-stone-100"),
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
]
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import htpy as h
|
|||
from htpy import Node, Renderable
|
||||
|
||||
from repub.components import (
|
||||
action_button,
|
||||
header_action_link,
|
||||
inline_link,
|
||||
input_field,
|
||||
|
|
@ -54,29 +55,6 @@ def _checked(source: Mapping[str, object] | None, key: str, default: bool) -> bo
|
|||
return bool(value)
|
||||
|
||||
|
||||
def _action_button(
|
||||
*,
|
||||
label: str,
|
||||
tone: str = "default",
|
||||
post_path: str | None = None,
|
||||
) -> Renderable:
|
||||
classes = {
|
||||
"default": "bg-stone-100 text-slate-700 hover:bg-stone-200",
|
||||
"danger": "bg-rose-50 text-rose-700 hover:bg-rose-100",
|
||||
}
|
||||
attributes: dict[str, str] = {}
|
||||
if post_path is not None:
|
||||
attributes["data-on:pointerdown"] = f"@post('{post_path}')"
|
||||
return h.button(
|
||||
attributes,
|
||||
type="button",
|
||||
class_=(
|
||||
"inline-flex items-center whitespace-nowrap rounded-full px-3 py-1.5 "
|
||||
f"text-sm font-semibold transition {classes[tone]}"
|
||||
),
|
||||
)[label]
|
||||
|
||||
|
||||
def _source_row(source: Mapping[str, object]) -> tuple[Node, ...]:
|
||||
return (
|
||||
h.div[
|
||||
|
|
@ -99,12 +77,12 @@ def _source_row(source: Mapping[str, object]) -> tuple[Node, ...]:
|
|||
),
|
||||
h.p(class_="mt-2 text-xs text-slate-500")[str(source["last_run"])],
|
||||
],
|
||||
h.div(class_="flex flex-nowrap items-center gap-3")[
|
||||
h.div(class_="flex flex-wrap items-center gap-2")[
|
||||
inline_link(
|
||||
href=f"/sources/{source['slug']}/edit", label="Edit", tone="amber"
|
||||
),
|
||||
inline_link(href="/runs", label="View runs"),
|
||||
_action_button(
|
||||
action_button(
|
||||
label="Delete",
|
||||
tone="danger",
|
||||
post_path=f"/actions/sources/{source['slug']}/delete",
|
||||
|
|
@ -422,10 +400,12 @@ def source_form(
|
|||
class_="flex flex-wrap justify-end gap-3 border-t border-slate-200 pt-6"
|
||||
)[
|
||||
muted_action_link(href="/sources", label="Cancel"),
|
||||
h.button(
|
||||
type="submit",
|
||||
class_="rounded-full bg-slate-950 px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-slate-800",
|
||||
)[submit_label],
|
||||
action_button(
|
||||
label=submit_label,
|
||||
tone="dark",
|
||||
emphasis="regular",
|
||||
button_type="submit",
|
||||
),
|
||||
],
|
||||
],
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue