zebflow 0.11.6

Reactive web automation platform — pipelines, templates, and real-time collaboration in a single binary.
Documentation
import { cx } from "zeb/react";

/**
 * Exposure is never quiet (`kinds/zebfs-acl` §Authority). A public folder or
 * file pulses amber; one that runs as a site pulses red with the addresses it
 * runs on. Both stop moving for a reader who asked for reduced motion, and
 * both say it in words, so the colour is never the only signal.
 */
export function ExposureMark({ access, inherited = false, serve = [] }) {
  if (access !== "public_read" && access !== "public_execute") return null;
  const execute = access === "public_execute";
  const label = execute ? "EXECUTE" : "PUBLIC";
  const hosts = execute
    ? (Array.isArray(serve) ? serve : []).map((origin) => String(origin).replace(/^https?:\/\//, "").replace(/\/$/, ""))
    : [];
  return (
    <span
      className={cx(
        "inline-flex items-center gap-1.5 shrink-0 rounded px-1.5 py-0.5 text-[0.62rem] font-semibold tracking-wide",
        execute ? "bg-red-500/15 text-red-400" : "bg-amber-400/15 text-amber-400",
      )}
      title={execute ? `Runs as a site on ${hosts.join(", ")}` : "Anyone can read this on the project's file host"}
    >
      <span className="relative inline-flex h-2 w-2">
        <span
          className={cx(
            "absolute inline-flex h-full w-full rounded-full animate-ping motion-reduce:animate-none",
            execute ? "bg-red-500" : "bg-amber-400",
          )}
        />
        <span className={cx("relative inline-flex h-2 w-2 rounded-full", execute ? "bg-red-500" : "bg-amber-400")} />
      </span>
      {label}
      {inherited ? <span className="font-normal opacity-80">· inherited</span> : null}
      {hosts.length > 0 ? <span className="font-normal opacity-90">→ {hosts.join(", ")}</span> : null}
    </span>
  );
}

/** A private folder with something exposed beneath it says so, collapsed or not. */
export function ExposedInsideMark({ count, execute }) {
  if (!count) return null;
  return (
    <span className={cx("shrink-0 text-[0.62rem] font-semibold", execute ? "text-red-400" : "text-amber-400")}>
      ⚠ {count} exposed inside
    </span>
  );
}

/** The rule set on exactly this path, or `null` when its exposure is inherited. */
export function ownRule(rules, path) {
  return (Array.isArray(rules) ? rules : []).find((rule) => rule.path === path) ?? null;
}

/** The exposed rules strictly beneath a folder. */
export function rulesInside(rules, folderPath) {
  const prefix = `${folderPath}/`;
  return (Array.isArray(rules) ? rules : []).filter((rule) => String(rule.path).startsWith(prefix));
}