Skip to content
114 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them.1/**
2 * Apps: every app in the workspace that you can use, the ones pinned to
3 * your dock first. Built-in apps are always in the dock; the rest you pin
4 * or unpin here, from the launcher, or on a phone from More. Pins are
The apps you pin to your dock are kept with your account, per workspace and in your order, so the dock is the same on every device: identity keeps them in dock_pins and answers dock_pins and set_dock_pins, the dock reads them with the rest of the page, pins kept only on this device carry over with your first change, this device's copy still draws the dock when identity can't be reached, a pin that can't be saved says so, and they go when you or the workspace do; the workspaces guide says how.5 * yours alone, per workspace, kept with your account so every device
6 * shows the same dock (lib/dock.server.ts), with a copy in a cookie for
7 * when the account's cannot be read (lib/apps.ts). The pin buttons post
8 * here.
g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them.9 */
10import { Store } from "lucide-react";
11import { data } from "react-router";
12
13import { hasCodeAccess } from "@g1t/contracts";
14
15import type { Route } from "./+types/apps";
16import { AppTile, useAppPins } from "../../components/apps";
The apps you pin to your dock are kept with your account, per workspace and in your order, so the dock is the same on every device: identity keeps them in dock_pins and answers dock_pins and set_dock_pins, the dock reads them with the rest of the page, pins kept only on this device carry over with your first change, this device's copy still draws the dock when identity can't be reached, a pin that can't be saved says so, and they go when you or the workspace do; the workspaces guide says how.17import { DOCK_COOKIE, type PinnableApp, appPinFromForm, appsFor, dockCookie, pinsToShow, withPin, writeDock } from "../../lib/apps";
18import { savePins, savedPins } from "../../lib/dock.server";
g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them.19import { page } from "../../lib/meta";
20import { readCookie } from "../../lib/mission";
21import { assertSameOrigin, getViewer, requireUser } from "../../lib/session.server";
22
23export function meta({ params, ...args }: Route.MetaArgs) {
24 return page(args, { title: `Apps · ${params.owner} · g1t` });
25}
26
The apps you pin to your dock are kept with your account, per workspace and in your order, so the dock is the same on every device: identity keeps them in dock_pins and answers dock_pins and set_dock_pins, the dock reads them with the rest of the page, pins kept only on this device carry over with your first change, this device's copy still draws the dock when identity can't be reached, a pin that can't be saved says so, and they go when you or the workspace do; the workspaces guide says how.27export async function loader({ params, context, request }: Route.LoaderArgs) {
g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them.28 const viewer = getViewer(context);
29 const slug = params.owner.toLowerCase();
30 const membership = viewer?.workspaces?.find((m) => m.slug === slug);
The apps you pin to your dock are kept with your account, per workspace and in your order, so the dock is the same on every device: identity keeps them in dock_pins and answers dock_pins and set_dock_pins, the dock reads them with the rest of the page, pins kept only on this device carry over with your first change, this device's copy still draws the dock when identity can't be reached, a pin that can't be saved says so, and they go when you or the workspace do; the workspaces guide says how.31 if (!viewer || !membership) throw data(null, { status: 404 });
g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them.32 return {
33 slug,
34 name: membership.name?.trim() || slug,
35 code: hasCodeAccess(membership),
The apps you pin to your dock are kept with your account, per workspace and in your order, so the dock is the same on every device: identity keeps them in dock_pins and answers dock_pins and set_dock_pins, the dock reads them with the rest of the page, pins kept only on this device carry over with your first change, this device's copy still draws the dock when identity can't be reached, a pin that can't be saved says so, and they go when you or the workspace do; the workspaces guide says how.36 pins: pinsToShow(await savedPins(viewer, slug), readCookie(request.headers.get("cookie"), DOCK_COOKIE), slug),
g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them.37 };
38}
39
40export async function action({ params, context, request }: Route.ActionArgs) {
41 assertSameOrigin(request);
42 const user = requireUser(context, request);
43 const slug = params.owner.toLowerCase();
44 if (!user.workspaces?.some((m) => m.slug === slug)) throw data(null, { status: 404 });
45 const change = appPinFromForm(await request.formData());
46 if (!change) return data({ error: "Nothing to do." }, { status: 400 });
The apps you pin to your dock are kept with your account, per workspace and in your order, so the dock is the same on every device: identity keeps them in dock_pins and answers dock_pins and set_dock_pins, the dock reads them with the rest of the page, pins kept only on this device carry over with your first change, this device's copy still draws the dock when identity can't be reached, a pin that can't be saved says so, and they go when you or the workspace do; the workspaces guide says how.47 const cookie = readCookie(request.headers.get("cookie"), DOCK_COOKIE);
48 // The change is made to the pins as the account keeps them; pins only
49 // ever kept in this device's cookie are carried over by the first one.
50 const current = pinsToShow(await savedPins(user, slug), cookie, slug);
51 const pins = await savePins(user, slug, withPin(current, change.app, change.pinned));
52 if (!pins) return data({ error: "Your pins could not be saved. Try again.", pins: current }, { status: 503 });
53 // This device's copy, drawn from when the account's cannot be read.
g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them.54 const secure = new URL(request.url).protocol === "https:";
The apps you pin to your dock are kept with your account, per workspace and in your order, so the dock is the same on every device: identity keeps them in dock_pins and answers dock_pins and set_dock_pins, the dock reads them with the rest of the page, pins kept only on this device carry over with your first change, this device's copy still draws the dock when identity can't be reached, a pin that can't be saved says so, and they go when you or the workspace do; the workspaces guide says how.55 return data({ error: null, pins }, { headers: { "Set-Cookie": dockCookie(writeDock(cookie, slug, pins), secure) } });
g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them.56}
57
58export default function Apps({ loaderData }: Route.ComponentProps) {
59 const { slug, name, code } = loaderData;
60 const { pins, toggle } = useAppPins(slug, loaderData.pins);
61 const apps = appsFor(code);
62 const pinned = pins.map((key) => apps.find((app) => app.key === key)).filter((app) => app != null);
63 return (
64 <main className="mx-auto max-w-5xl px-4 py-8 sm:px-8 sm:py-10">
65 <div className="flex flex-wrap items-end justify-between gap-4">
66 <div>
67 <h1 className="text-2xl font-semibold tracking-tight">Apps</h1>
68 <p className="mt-1 max-w-xl text-sm text-muted">
69 Everything in {name} that you can use. Pin the ones you want in your dock: your dock is yours, and nobody else sees your pins.
70 </p>
71 </div>
72 <span className="inline-flex h-9 items-center gap-2 rounded-md border border-line px-3 text-sm text-faint">
73 <Store size={15} />
74 Marketplace
75 <span className="rounded-full bg-line px-1.5 text-[0.6875rem] font-medium text-muted">Coming</span>
76 </span>
77 </div>
78
79 <section aria-labelledby="pinned" className="mt-8">
80 <div className="flex items-baseline justify-between gap-3">
81 <h2 id="pinned" className="text-sm font-semibold">
82 Pinned to your dock
83 </h2>
84 <span className="text-xs text-faint">{pinned.length === 0 ? "None yet" : `${pinned.length} pinned`}</span>
85 </div>
86 {pinned.length === 0 ? (
87 <p className="mt-3 rounded-xl border border-dashed border-line px-4 py-6 text-center text-sm text-muted">
88 Nothing pinned yet. Pin an app below and it shows in your dock, under the built-in ones.
89 </p>
90 ) : (
91 <div className="mt-3 grid grid-cols-[repeat(auto-fill,minmax(15rem,1fr))] gap-2">
92 {pinned.map((app) => (
93 <AppTile key={app.key} app={app} slug={slug} pinned onToggle={toggle} card />
94 ))}
95 </div>
96 )}
97 </section>
98
99 <section aria-labelledby="yours" className="mt-10">
100 <div className="flex items-baseline justify-between gap-3">
101 <h2 id="yours" className="text-sm font-semibold">
102 Your apps
103 </h2>
104 <span className="text-xs text-faint">Built-in apps are always in your dock</span>
105 </div>
106 <div className="mt-3 grid grid-cols-[repeat(auto-fill,minmax(15rem,1fr))] gap-2">
107 {apps.map((app) => (
108 <AppTile key={app.key} app={app} slug={slug} pinned={pins.includes(app.key as PinnableApp)} onToggle={toggle} card />
109 ))}
110 </div>
111 </section>
112 </main>
113 );
114}