Skip to content

Commit

Docs: the search stays centred on every page, and the site works on a phone

The header was Starlight's row, whose first column follows the page body, so the search moved with the sidebar and the On this page list. It is now our own three-column row with equal sides, the same on every page. On tablets and phones: a full search box from 45rem, a 40px search icon below; header icons and the menu button at 40px; tabs that scroll sideways; Copy page kept beside the title as icon buttons; wide tables and code that scroll inside themselves; endpoint paths that wrap; Sign up readable in the phone menu. Search results no longer quote the Copy page menu. The add-collaborator description gets back its lost "A `".

syntaqxcommitted Parent6f82ff4Browse files
6 files+209−240/6 viewed
+1−1
45954595 "expires_at": "2026-10-12T17:00:00.000Z"
45964596 }
45974597 },
4598− "notes": "`invitee` is a username or an email address. A member of the workspace answers `{\"result\": \"granted\", \"collaborator\": {…}}` with the role already given, shown as list_collaborators shows a person. Anyone else answers `{\"result\": \"invited\", \"invitation\": {…}}`: the invitation is emailed and waits 7 days, and the role is theirs once they accept it. An email address without an account gets an invitation with `email` set and `invitee` null, and an invite that makes the account and accepts in one step. Refused with `404` when no account has that username, `409` when they already have a role of their own or a pending invitation (change it with update_collaborator), and `403` without the Admin role, from an agent's or a workspace's token, or when the person does not meet what the workspace asks of everyone with access. collaborator_added` webhook event is sent once they have the role. See [Access and roles](/guides/access-and-roles/). On a free workspace, inviting anyone who is not a member answers `402` with `payment_required` until it starts the g1t plan."
4598+ "notes": "`invitee` is a username or an email address. A member of the workspace answers `{\"result\": \"granted\", \"collaborator\": {…}}` with the role already given, shown as list_collaborators shows a person. Anyone else answers `{\"result\": \"invited\", \"invitation\": {…}}`: the invitation is emailed and waits 7 days, and the role is theirs once they accept it. An email address without an account gets an invitation with `email` set and `invitee` null, and an invite that makes the account and accepts in one step. Refused with `404` when no account has that username, `409` when they already have a role of their own or a pending invitation (change it with update_collaborator), and `403` without the Admin role, from an agent's or a workspace's token, or when the person does not meet what the workspace asks of everyone with access. A `collaborator_added` webhook event is sent once they have the role. See [Access and roles](/guides/access-and-roles/). On a free workspace, inviting anyone who is not a member answers `402` with `payment_required` until it starts the g1t plan."
45994599 },
46004600 "update_collaborator": {
46014601 "params": {
+63−6
11 ---
2−// Starlight's header, with the tabs that divide the docs beneath it.
3−import Default from '@astrojs/starlight/components/Header.astro';
2+// The docs header: the wordmark, search in the middle and links on the
3+// right, with the tabs that divide the docs beneath it.
4+//
5+// Its own layout, not Starlight's: Starlight lines the search up with the
6+// page's text column, which moves when a page has an "On this page" list
7+// and when it does not. Here the row is three columns, the outer two always
8+// the same width, so the search sits at the header's centre on every page.
9+import Search from '@astrojs/starlight/components/Search.astro';
410
511 import { TABS, tabFor } from '../tabs';
12+import SiteTitle from './SiteTitle.astro';
13+import SocialIcons from './SocialIcons.astro';
614
715 const current = tabFor(Astro.locals.starlightRoute.id);
816 ---
917
1018 <div class="g1t-header">
11− <div class="g1t-header-top"><Default /></div>
19+ <div class="g1t-header-top">
20+ <div class="g1t-header-title"><SiteTitle /></div>
21+ <div class="g1t-header-search print:hidden"><Search /></div>
22+ <div class="g1t-header-links print:hidden"><SocialIcons /></div>
23+ </div>
1224 <nav class="g1t-tabs" aria-label="Sections">
1325 {
1426 TABS.map((tab) => (
2840 }
2941 /* The same bar as the app's: 3.5rem, and a line under it. */
3042 .g1t-header-top {
43+ /* Each side column is at least as wide as the widest thing that goes
44+ in either, so the two stay equal and the search stays centred. */
45+ --g1t-header-side: 13.5rem;
3146 box-sizing: border-box;
47+ display: grid;
48+ grid-template-columns:
49+ minmax(var(--g1t-header-side), 1fr)
50+ minmax(0, 26rem)
51+ minmax(var(--g1t-header-side), 1fr);
52+ align-items: center;
53+ gap: 1rem;
3254 height: 3.5rem;
3355 flex-shrink: 0;
3456 padding: 0 var(--sl-nav-pad-x);
3557 border-bottom: 1px solid var(--g1t-line);
3658 }
37− /* On phones the menu button sits at the top row's end: leave it room. */
59+ .g1t-header-title {
60+ display: flex;
61+ min-width: 0;
62+ /* Room for the link's focus ring. */
63+ padding: 0.25rem;
64+ margin: -0.25rem;
65+ }
66+ .g1t-header-search {
67+ display: flex;
68+ justify-content: center;
69+ min-width: 0;
70+ }
71+ .g1t-header-links {
72+ display: flex;
73+ justify-content: flex-end;
74+ min-width: 0;
75+ }
76+ /* Tablets: the sidebar is a menu, and its button (fixed in place by
77+ Starlight) takes the row's end. The right column makes room for it
78+ inside itself, so the two columns stay equal and the search centred. */
3879 @media (max-width: 49.99rem) {
39− :global([data-has-sidebar]) .g1t-header-top {
40− padding-inline-end: calc(var(--sl-nav-pad-x) + var(--sl-menu-button-size) + var(--sl-nav-gap));
80+ .g1t-header-top {
81+ --g1t-header-side: 13rem;
82+ }
83+ :global([data-has-sidebar]) .g1t-header-links {
84+ padding-inline-end: calc(var(--sl-menu-button-size) + 0.5rem);
4185 }
4286 }
87+ /* Phones: the wordmark on the left; search, the links and the menu
88+ button together on the right. */
89+ @media (max-width: 44.99rem) {
90+ .g1t-header-top {
91+ grid-template-columns: minmax(0, 1fr) auto auto;
92+ gap: 0.25rem;
93+ }
94+ }
4395 .g1t-tabs {
4496 display: flex;
4597 gap: 1.5rem;
4698 height: 2.75rem;
4799 padding: 0 var(--sl-nav-pad-x);
48100 overflow-x: auto;
101+ overscroll-behavior-x: contain;
49102 scrollbar-width: none;
50103 }
104+ .g1t-tabs::-webkit-scrollbar {
105+ display: none;
106+ }
51107 .g1t-tabs a {
52108 display: flex;
109+ flex-shrink: 0;
53110 align-items: center;
54111 border-bottom: 1.5px solid transparent;
55112 font-size: 0.875rem;
+37−2
1414 <div class="g1t-page-title">
1515 <div class="g1t-page-title-row">
1616 <h1 id="_top">{title}</h1>
17− <div class="g1t-copy not-content">
17+ <div class="g1t-copy not-content" data-pagefind-ignore>
1818 <button type="button" class="g1t-copy-main" data-markdown={markdown}>
1919 <Copy />
2020 <span>Copy page</span>
224224 font-size: 0.75rem;
225225 color: var(--g1t-faint);
226226 }
227+ /* Phones: the group keeps its place beside the title, as two square
228+ buttons a finger can hit; the copy button shows only its icon, and
229+ its label stays for screen readers. */
227230 @media (max-width: 40rem) {
231+ .g1t-page-title-row {
232+ gap: 0.75rem;
233+ }
234+ h1 {
235+ min-width: 0;
236+ font-size: 1.75rem;
237+ overflow-wrap: anywhere;
238+ }
228239 .g1t-copy {
229− display: none;
240+ height: 2.5rem;
241+ margin-top: 0;
242+ }
243+ .g1t-copy-main span {
244+ position: absolute;
245+ width: 1px;
246+ height: 1px;
247+ overflow: hidden;
248+ clip-path: inset(50%);
249+ white-space: nowrap;
250+ }
251+ .g1t-copy-main,
252+ .g1t-copy-more summary {
253+ width: 2.5rem;
254+ padding: 0;
255+ }
256+ .g1t-copy :global(svg) {
257+ width: 1rem;
258+ height: 1rem;
259+ }
260+ .g1t-copy-menu {
261+ width: min(16.5rem, calc(100vw - 2rem));
262+ }
263+ .g1t-copy-menu a {
264+ padding-block: 0.65rem;
230265 }
231266 }
232267 </style>
+35−10
2020 align-items: center;
2121 gap: 0.25rem;
2222 }
23− a {
23+ /* nav.g1t-nav: the menu's own link rule must not win where these sit
24+ at the foot of the phone menu. */
25+ nav.g1t-nav a {
26+ display: inline-flex;
27+ align-items: center;
28+ height: 2rem;
2429 border-radius: 0.4rem;
25− padding: 0.3rem 0.6rem;
30+ padding: 0 0.6rem;
2631 font-size: 0.85rem;
32+ white-space: nowrap;
2733 color: var(--g1t-muted);
2834 text-decoration: none;
2935 transition: color 0.15s, background 0.15s;
3036 }
31− a:hover {
37+ nav.g1t-nav a:hover {
3238 background: var(--g1t-raised);
3339 color: var(--g1t-fg);
3440 }
35− .g1t-nav-cta {
41+ nav.g1t-nav .g1t-nav-cta {
3642 margin-left: 0.25rem;
3743 background: var(--g1t-fg);
3844 color: var(--g1t-bg);
3945 font-weight: 500;
4046 }
41− .g1t-nav-cta:hover {
47+ nav.g1t-nav .g1t-nav-cta:hover {
4248 background: #fff;
4349 color: var(--g1t-bg);
4450 }
45− .g1t-nav-icon {
46− display: inline-flex;
47− padding: 0.4rem;
51+ nav.g1t-nav .g1t-nav-icon {
52+ justify-content: center;
53+ width: 2rem;
54+ padding: 0;
4855 }
4956 .g1t-nav-icon :global(svg) {
5057 width: 1rem;
5158 height: 1rem;
5259 }
53− @media (max-width: 50rem) {
54− a:not(.g1t-nav-icon):not(.g1t-nav-cta) {
60+ /* Tablets and phones: in the header g1t.sh's link gives way (the menu
61+ keeps it), and the icons grow to a size a finger can hit. */
62+ @media (max-width: 49.99rem) {
63+ :global(.g1t-header) nav.g1t-nav a:not(.g1t-nav-icon):not(.g1t-nav-cta) {
64+ display: none;
65+ }
66+ nav.g1t-nav .g1t-nav-icon {
67+ width: 2.5rem;
68+ height: 2.5rem;
69+ }
70+ :global(.sidebar-content) nav.g1t-nav a {
71+ height: 2.5rem;
72+ }
73+ }
74+ /* Phones: Sign up leaves the header for the menu, where it has room. */
75+ @media (max-width: 44.99rem) {
76+ :global(.g1t-header) .g1t-nav {
77+ gap: 0;
78+ }
79+ :global(.g1t-header) nav.g1t-nav .g1t-nav-cta {
5580 display: none;
5681 }
5782 }
+0−0

Binary or large file; its contents are not shown.

+73−5
4141 beneath it. */
4242 --sl-nav-height: 6.25rem;
4343 --sl-sidebar-width: 17rem;
44+ /* Big enough to tap. */
45+ --sl-menu-button-size: 2.5rem;
4446
4547 color-scheme: dark;
4648 }
6264 backdrop-filter: blur(10px);
6365 border-bottom: 1px solid var(--g1t-line);
6466 }
67+/* The search box fills the header's middle column; Header.astro centres
68+ that column in the header, the same on every page. */
6569 site-search {
70+ display: flex;
71+ justify-content: center;
6672 width: 100%;
67− max-width: 30rem;
68−}
69−/* On phones the menu button sits in the header's top row, not its middle. */
70−.sl-menu-button {
71− top: calc((3.5rem - var(--sl-menu-button-size)) / 2) !important;
7273 }
7374 site-search button[data-open-modal] {
7475 border-radius: 0.5rem;
8081 border-color: var(--g1t-line-strong);
8182 color: var(--g1t-muted);
8283 }
84+@media (min-width: 50rem) {
85+ site-search button[data-open-modal] {
86+ max-width: none;
87+ }
88+}
89+/* Tablets: the full search box, as on desktop, since there is room. */
90+@media (min-width: 45rem) and (max-width: 49.99rem) {
91+ site-search button[data-open-modal] {
92+ width: 100%;
93+ border: 1px solid var(--g1t-line);
94+ padding-inline: 0.75rem 0.5rem;
95+ font-size: var(--sl-text-sm);
96+ }
97+ site-search button[data-open-modal] > span.sl-hidden {
98+ display: block;
99+ }
100+ site-search button[data-open-modal] > kbd.sl-hidden {
101+ display: flex;
102+ margin-inline-start: auto;
103+ }
104+}
105+/* Phones: a search icon, as big as a fingertip. */
106+@media (max-width: 44.99rem) {
107+ site-search button[data-open-modal] {
108+ justify-content: center;
109+ width: 2.5rem;
110+ height: 2.5rem;
111+ padding: 0;
112+ border: 0;
113+ background: transparent;
114+ color: var(--g1t-muted);
115+ font-size: 1.125rem;
116+ }
117+}
118+/* The menu button sits in the header's top row, at the end, drawn like
119+ the header's other icon buttons rather than as a floating disc. */
120+.sl-menu-button {
121+ top: calc((3.5rem - var(--sl-menu-button-size)) / 2) !important;
122+ align-items: center;
123+ justify-content: center;
124+ border-radius: 0.5rem;
125+ padding: 0;
126+ background: transparent;
127+ box-shadow: none;
128+ color: var(--g1t-fg-soft);
129+ font-size: 1.25rem;
130+}
131+.sl-menu-button:hover,
132+.sl-menu-button:has(~ :popover-open) {
133+ background: var(--g1t-raised);
134+ color: var(--g1t-fg);
135+}
83136
84137 /* --- Sidebar -------------------------------------------------------------- */
85138
217270 overflow-wrap: normal;
218271 word-break: normal;
219272 }
273+ /* The last column usually holds the sentences. Kept readable, it
274+ scrolls the table sideways instead of folding to a word a line. */
275+ .sl-markdown-content :is(td, th):last-child:not(:first-child) {
276+ min-width: 12rem;
277+ }
220278 }
221279 .sl-markdown-content th {
222280 border-bottom: 1px solid var(--g1t-line-strong);
397455 white-space: nowrap;
398456 color: var(--g1t-fg);
399457 }
458+/* On a phone a long path wraps onto a second line rather than hiding its end. */
459+@media (max-width: 40rem) {
460+ .sl-markdown-content .g1t-endpoint {
461+ align-items: flex-start;
462+ }
463+ .sl-markdown-content .g1t-endpoint code {
464+ white-space: normal;
465+ overflow-wrap: anywhere;
466+ }
467+}
400468 /* Methods: the same small mono tag in the sidebar and on the page. */
401469 .g1t-method {
402470 --method: var(--g1t-muted);