Add prosekit rich-text field, Gitea repo embeds, automation KV read endpoint; fix apex/www session-cookie mismatch on /auth/callback
Deploy / deploy (push) Successful in 29s
Deploy / deploy (push) Successful in 29s
- type: prosekit requirement kind, backed by public/prosekit-editor.js
(ProseMirror via prosekit, loaded from esm.sh, no bundler) - mirrors
its HTML into a paired hidden input so it reuses the existing
RwSignal/on:input wiring.
- Pasting a project.uhhm.no/<owner>/<repo> URL in the editor embeds a
repo card, resolved server-side via a new /gitea-repo handler
(content::gitea_repo_handler) so the browser never needs Gitea API
CORS.
- New /automation/kv/{bucket} handler, bearer-token gated
(AUTOMATION_READ_TOKEN), for backing automations (n8n) to read a
NATS KV bucket without a browser session.
- Fix: a login started on one of apex/www set its session cookie
there, but Kanidm's redirect_uri is fixed to PUBLIC_URL - landing
the callback on a different, empty session ("no login in
progress"). Caddy now redirects www -> apex so every visit stays on
one canonical host.
This commit is contained in:
+59
-1
@@ -198,6 +198,31 @@ mod yes {
|
||||
}
|
||||
}
|
||||
|
||||
// Same idiomatic-typed-module approach as `yes` above, for the
|
||||
// prosekit-backed rich-text requirement kind (`prosekit-editor.js`,
|
||||
// project root - `#[wasm_bindgen(module = "/x.js")]` resolves relative
|
||||
// to the crate root, not the `public/` static-asset dir, same as
|
||||
// `yes.js` below). `mount_editor` hands the editor a container node
|
||||
// plus the paired
|
||||
// hidden `<input>` it mirrors its HTML into and fires real `input`
|
||||
// events on - see `mount_editor`'s call site in `AlternativeCard`, and
|
||||
// the JS module itself for why a hidden-input bridge rather than a
|
||||
// bespoke Rust<->JS value channel.
|
||||
#[cfg(feature = "hydrate")]
|
||||
mod prosekit {
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen(module = "/prosekit-editor.js")]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_name = mountEditor)]
|
||||
pub fn mount_editor(
|
||||
container: &web_sys::HtmlDivElement,
|
||||
hidden: &web_sys::HtmlInputElement,
|
||||
initial: &str,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Hero(title: String, description: String, show_yes: bool) -> impl IntoView {
|
||||
// Only the landing page gets the full interactive piece - it's the
|
||||
@@ -427,6 +452,8 @@ fn AlternativeCard(
|
||||
</span>
|
||||
};
|
||||
|
||||
let sig = field_map.get(&req.name).copied().unwrap_or_else(|| RwSignal::new(String::new()));
|
||||
|
||||
if req.kind == "file" {
|
||||
let file_ref = file_refs.get(&req.name).copied().unwrap_or_else(NodeRef::new);
|
||||
return view! {
|
||||
@@ -445,7 +472,38 @@ fn AlternativeCard(
|
||||
.into_any();
|
||||
}
|
||||
|
||||
let sig = field_map.get(&req.name).copied().unwrap_or_else(|| RwSignal::new(String::new()));
|
||||
if req.kind == "prosekit" {
|
||||
let container_ref: NodeRef<leptos::html::Div> = NodeRef::new();
|
||||
let hidden_ref: NodeRef<leptos::html::Input> = NodeRef::new();
|
||||
|
||||
#[cfg(feature = "hydrate")]
|
||||
{
|
||||
Effect::new(move |_| {
|
||||
let (Some(container), Some(hidden)) =
|
||||
(container_ref.get(), hidden_ref.get())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
prosekit::mount_editor(&container, &hidden, &sig.get_untracked());
|
||||
});
|
||||
}
|
||||
|
||||
return view! {
|
||||
<label class="field" for=label_for>
|
||||
{label_text}
|
||||
<input
|
||||
id=field_id
|
||||
type="hidden"
|
||||
node_ref=hidden_ref
|
||||
prop:value=move || sig.get()
|
||||
on:input=move |ev| sig.set(event_target_value(&ev))
|
||||
/>
|
||||
<div class="prosekit-editor" node_ref=container_ref></div>
|
||||
</label>
|
||||
}
|
||||
.into_any();
|
||||
}
|
||||
|
||||
view! {
|
||||
<label class="field" for=label_for>
|
||||
{label_text}
|
||||
|
||||
Reference in New Issue
Block a user