time-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 4857f8a940b5
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 703ed60f2cc5ad3d98a5bf4a
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
src/main.tsx
// Time's entry. "/" keeps the static landing and mounts the start box into its hero; every other path
// (/timer, /timesheet, /reports, /projects, /settings, /join/<id>) hides the landing and shows the app.
import { createRoot } from "react-dom/client";
import { usePath } from "./lib/router";
import { Toaster } from "./ui";
import { Start } from "./Start";
import { Shell, routeOf } from "./Shell";
import "./styles.css";

function App() {
  const path = usePath();
  const route = routeOf(path);
  document.body.classList.toggle("app-mode", Boolean(route));
  return (
    <>
      {route ? <Shell route={route} /> : null}
      <Toaster />
    </>
  );
}

createRoot(document.getElementById("app")!).render(<App />);
const start = document.getElementById("start");
if (start) createRoot(start).render(<Start />);

// In-page links (the landing's start box and nav) move without a reload.
document.addEventListener("click", (e) => {
  const a = (e.target as HTMLElement).closest?.("a[data-app]") as HTMLAnchorElement | null;
  if (!a || e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0) return;
  e.preventDefault();
  history.pushState(null, "", a.getAttribute("href")!);
  window.dispatchEvent(new PopStateEvent("popstate"));
  window.scrollTo(0, 0);
});

if (import.meta.env.PROD && "serviceWorker" in navigator) {
  window.addEventListener("load", () => void navigator.serviceWorker.register("/sw.js").catch(() => null));
}

const head = document.querySelector(".site-head");
const onScroll = () => head?.classList.toggle("scrolled", window.scrollY > 4);
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();

Change history

Point OpenApps links to openapps.free
4857f8a940 · 19 hours ago
Bind agent address constants in policy
62b1e6acb2 · 20 hours ago
Use functions.openapps.xyz alias and add OpenApp contribution strip
61d972193a · 20 hours ago
Bounded source sync
fc644b4327 · 1 day ago
Bounded source sync
22f511f3db · 1 day ago
Bounded source sync
351a8d754c · 1 day ago
Bounded source sync
0da238a77e · 1 day ago