@korso/shepherd-ui 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { jsx as e, jsxs as l } from "react/jsx-runtime";
2
2
  import { useState as s, useMemo as h } from "react";
3
- import { c as d, a as m, D as u } from "./Dashboard-Bgi50wCo.js";
3
+ import { c as d, a as m, D as u } from "./Dashboard-CTXdGRxM.js";
4
4
  const i = "shepherd.token";
5
5
  function p() {
6
6
  try {
@@ -46,6 +46,56 @@
46
46
  background:transparent; cursor:pointer; font:inherit; }
47
47
  .tab--active { background:var(--ink); color:var(--bg); }
48
48
 
49
+ /* Workspace switcher (app-bar): the active-workspace indicator + the one
50
+ home for switch/create/join. Shown on every tab. */
51
+ .ws-switcher { position:relative; }
52
+ .ws-trig { display:inline-flex; align-items:center; gap:8px; font:inherit; font-size:13px;
53
+ font-weight:600; color:var(--ink); cursor:pointer;
54
+ border:1px solid var(--line); border-radius:9px; padding:5px 10px; background:var(--card); }
55
+ .ws-trig:hover { border-color:var(--ink3); }
56
+ .ws-trig--empty { background:transparent; border-style:dashed; border-color:var(--ink2); }
57
+ .ws-avatar { width:18px; height:18px; border-radius:6px; background:var(--ink); color:var(--bg);
58
+ display:grid; place-items:center; font-size:10px; font-weight:700; flex:none; }
59
+ .ws-avatar--sm { width:16px; height:16px; font-size:9px; }
60
+ .ws-plus { color:var(--ink2); font-weight:700; }
61
+ .ws-name { max-width:180px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
62
+ .ws-caret { color:var(--ink3); font-size:10px; }
63
+
64
+ .ws-menu { position:absolute; top:40px; left:0; width:240px; z-index:20;
65
+ background:var(--card); border:1px solid var(--line); border-radius:11px; padding:6px;
66
+ box-shadow:0 8px 24px rgba(50,40,20,.16); }
67
+ .ws-menu__head { margin:0; padding:6px 8px; font-size:10px; letter-spacing:.08em;
68
+ text-transform:uppercase; color:var(--ink3); }
69
+ .ws-menu__none { margin:0; padding:2px 8px 6px; color:var(--ink3); font-style:italic; font-size:13px; }
70
+ .ws-menu__list { list-style:none; margin:0; padding:0; }
71
+ .ws-mi { display:flex; align-items:center; gap:8px; width:100%; text-align:left; font:inherit;
72
+ font-size:13px; color:var(--ink); background:transparent; border:0; border-radius:7px;
73
+ padding:7px 8px; cursor:pointer; }
74
+ .ws-mi:hover { background:var(--chip); }
75
+ .ws-mi--on { font-weight:600; }
76
+ .ws-mi__name { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
77
+ .ws-mi__check { color:var(--live); }
78
+ .ws-menu__actions { display:flex; flex-direction:column; margin-top:5px; padding-top:5px;
79
+ border-top:1px solid var(--line2); }
80
+ .ws-action { display:flex; align-items:center; gap:8px; width:100%; text-align:left; font:inherit;
81
+ font-size:13px; color:var(--ink2); background:transparent; border:0; border-radius:7px;
82
+ padding:8px; cursor:pointer; }
83
+ .ws-action:hover { background:var(--chip); color:var(--ink); }
84
+
85
+ .ws-form { display:flex; flex-direction:column; gap:8px; padding:4px; }
86
+ .ws-form label { font-size:10px; font-weight:600; letter-spacing:.05em; text-transform:uppercase;
87
+ color:var(--ink3); }
88
+ .ws-form input { padding:8px 10px; border-radius:8px; border:1px solid var(--line);
89
+ background:var(--bg); color:var(--ink); font:inherit; }
90
+ .ws-form input:focus { outline:none; border-color:var(--terr); box-shadow:0 0 0 3px rgba(122,106,72,.14); }
91
+ .ws-form__row { display:flex; gap:8px; justify-content:flex-end; }
92
+ .ws-form__row button { font:inherit; font-size:13px; font-weight:600; border-radius:8px;
93
+ padding:7px 14px; cursor:pointer; border:1px solid var(--ink); background:var(--ink); color:var(--bg); }
94
+ .ws-form__row button:disabled { opacity:.55; cursor:default; }
95
+ .ws-form__back { background:transparent !important; color:var(--ink2) !important;
96
+ border-color:var(--line) !important; }
97
+ .ws-menu__error { margin:6px 4px 2px; font-size:12.5px; color:var(--drop); }
98
+
49
99
  /* Crew strip */
50
100
  .crew { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:26px 0 32px; }
51
101
  .person { display:inline-flex; align-items:center; gap:9px; padding:5px 13px 5px 5px;
@@ -187,11 +237,40 @@
187
237
  .shepherd-config { display:flex; flex-direction:column; }
188
238
  .shepherd-config h2 { font-size:16px; margin:0 0 22px; }
189
239
 
190
- /* Flat sections: no card chrome. Each section sits directly on the page;
191
- consecutive sections are set off by a hairline rather than a box. */
192
- .shepherd-config > section { padding:26px 0; }
193
- .shepherd-config > section:first-of-type { padding-top:0; }
194
- .shepherd-config > section + section { border-top:1px solid var(--line2); }
240
+ /* Config sidebar: a left nav of sections beside the active section's
241
+ panel, replacing the old single long scroll. */
242
+ .config-layout { display:flex; gap:32px; align-items:flex-start; }
243
+ .config-nav { flex:none; width:170px; display:flex; flex-direction:column; gap:2px;
244
+ position:sticky; top:0; }
245
+ /* Scoped under .shepherd-config to out-specify the generic dark-fill
246
+ `.shepherd-config button` rule — these are plain nav links, not buttons. */
247
+ .shepherd-config .config-nav__item { text-align:left; font:inherit; font-size:13.5px;
248
+ color:var(--ink2); background:transparent; border:0; border-radius:8px; padding:8px 12px;
249
+ cursor:pointer; box-shadow:inset 2px 0 0 transparent; transition:color .12s ease, background .12s ease; }
250
+ /* Extra .config-nav in the chain so this out-specifies the generic dark
251
+ `.shepherd-config button:hover` fill — a translucent tint, not a block. */
252
+ .shepherd-config .config-nav .config-nav__item:hover { color:var(--ink);
253
+ background:rgba(50,44,32,.06); }
254
+ .shepherd-config .config-nav__item--on { color:var(--ink); font-weight:600;
255
+ box-shadow:inset 2px 0 0 var(--ink); }
256
+ .shepherd-config .config-nav .config-nav__item--on:hover { background:transparent; }
257
+ .config-panel { flex:1; min-width:0; }
258
+
259
+ /* Two sections can share a panel (Members + Invites); set them off by a
260
+ hairline, mirroring the old flat-section separation. */
261
+ .config-panel > section + section { margin-top:26px; padding-top:26px;
262
+ border-top:1px solid var(--line2); }
263
+
264
+ /* No-workspace Config prompt (create/join now live in the switcher). */
265
+ .config-none { color:var(--ink2); font-size:13.5px; max-width:520px; }
266
+
267
+ /* Read-only workspace facts (name / role) in General. */
268
+ .shepherd-config .readonly-value { margin:0; font-size:14px; color:var(--ink);
269
+ padding:9px 12px; border-radius:8px; border:1px solid var(--line2); background:var(--bg); }
270
+ .shepherd-general .leave { padding-top:4px; }
271
+ .shepherd-config button.danger { border-color:var(--drop); background:transparent; color:var(--drop);
272
+ align-self:flex-start; }
273
+ .shepherd-config button.danger:hover:not(:disabled) { background:var(--drop); color:var(--bg); }
195
274
  .shepherd-config .card-head h3 {
196
275
  font-size:13px; font-weight:600; letter-spacing:.04em; text-transform:uppercase;
197
276
  color:var(--ink2); margin:0; }
@@ -215,10 +294,10 @@
215
294
  .shepherd-config .field__row { display:flex; gap:10px; align-items:center; flex-wrap:wrap; }
216
295
  .shepherd-config .field__row > input { flex:1; min-width:200px; }
217
296
 
218
- /* Admin zone (invites) is set off from create/join by a hairline. */
219
- .shepherd-workspaces .admin { display:flex; flex-direction:column; gap:14px;
220
- padding-top:16px; border-top:1px solid var(--line2); }
221
- .shepherd-workspaces .invites { display:flex; flex-direction:column; gap:10px; align-items:flex-start; }
297
+ /* Invite-by-code: a compact button with the freshly-created code shown
298
+ above it (the button below mints another). */
299
+ .shepherd-invites .invites { gap:12px; }
300
+ .shepherd-invites .invites > button { align-self:flex-start; }
222
301
 
223
302
  .shepherd-config input, .shepherd-config select {
224
303
  padding:9px 12px; border-radius:8px; border:1px solid var(--line);
@@ -252,21 +331,52 @@
252
331
  border:1px solid var(--line); background:var(--bg); color:var(--ink);
253
332
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:12px; line-height:1.5;
254
333
  overflow-x:auto; white-space:pre-wrap; word-break:break-word; }
255
- .shepherd-connect-agent .install-command__copy {
256
- position:absolute; top:8px; right:8px; padding:4px 10px; font-size:11px;
257
- border-radius:6px; border:1px solid var(--line); background:var(--card);
258
- color:var(--ink2); cursor:pointer; transition:background .12s ease, color .12s ease; }
259
- .shepherd-connect-agent .install-command__copy:hover { background:var(--ink); color:var(--bg); }
334
+ /* Bare icon button (clipboard → check on copy), not a filled pill. Extra
335
+ selector depth beats the generic dark `.shepherd-config button` fill. */
336
+ .shepherd-config .shepherd-connect-agent .install-command__copy {
337
+ position:absolute; top:7px; right:7px; display:grid; place-items:center;
338
+ width:28px; height:28px; padding:0; border-radius:7px; border:0;
339
+ background:transparent; color:var(--ink3); cursor:pointer;
340
+ transition:background .12s ease, color .12s ease; }
341
+ .shepherd-config .shepherd-connect-agent .install-command__copy:hover {
342
+ background:rgba(50,44,32,.08); color:var(--ink); }
260
343
  .shepherd-connect-agent h4 { margin:6px 0 0; font-size:11px; font-weight:600;
261
344
  letter-spacing:.05em; text-transform:uppercase; color:var(--ink3); }
262
345
 
263
- .shepherd-config .invite-result, .shepherd-connect-agent .token-once {
346
+ .shepherd-connect-agent .token-once {
264
347
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:12px;
265
348
  padding:10px 12px; border-radius:8px;
266
349
  background:var(--chip); border:1px solid var(--line2); }
267
- .shepherd-config .invite-result { display:flex; flex-direction:column; gap:8px; word-break:break-all; }
268
- .shepherd-config .invite-result__row { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
269
- .shepherd-config .invite-result a { color:var(--ink2); }
350
+
351
+ /* Created-invite card: an eyebrow + use count + a quiet Revoke, then the
352
+ code and join link each with their own Copy affordance. */
353
+ .shepherd-config .invite-result { align-self:stretch; display:flex; flex-direction:column;
354
+ gap:12px; padding:14px 16px; border-radius:10px; background:var(--card);
355
+ border:1px solid var(--line); }
356
+ .shepherd-config .invite-result__head { display:flex; align-items:center; gap:12px; }
357
+ .shepherd-config .invite-result__eyebrow { flex:1; font-size:11px; font-weight:600;
358
+ letter-spacing:.05em; text-transform:uppercase; color:var(--ink3); }
359
+ .shepherd-config .invite-uses { font-size:12px; color:var(--ink3); }
360
+ .shepherd-config .invite-result__copyrow { display:flex; align-items:center; gap:10px; }
361
+ .shepherd-config .invite-result__copyrow > code { flex:1; min-width:0; font-size:15px;
362
+ font-weight:600; font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
363
+ color:var(--ink); letter-spacing:.02em; word-break:break-all; }
364
+ .shepherd-config .invite-result__copyrow--link { padding-top:10px;
365
+ border-top:1px solid var(--line2); }
366
+ .shepherd-config .invite-result__copyrow--link a { flex:1; min-width:0; font-size:12px;
367
+ color:var(--ink2); word-break:break-all; }
368
+
369
+ /* Quiet buttons inside the card: a bordered Copy pill and a text-only
370
+ Revoke. Extra selector depth beats the generic dark `button` fill+hover. */
371
+ .shepherd-config .invite-result .copy-btn { flex:none; padding:5px 12px; font-size:12px;
372
+ font-weight:600; border-radius:7px; border:1px solid var(--line); background:var(--bg);
373
+ color:var(--ink2); cursor:pointer; }
374
+ .shepherd-config .invite-result .copy-btn:hover { background:var(--ink); color:var(--bg);
375
+ border-color:var(--ink); }
376
+ .shepherd-config .invite-result .link-btn { flex:none; padding:0; font-size:12px;
377
+ font-weight:600; border:0; background:transparent; color:var(--drop); cursor:pointer; }
378
+ .shepherd-config .invite-result .link-btn:hover { background:transparent;
379
+ text-decoration:underline; }
270
380
  .shepherd-config .revoked { color:var(--ink3); text-decoration:line-through; }
271
381
  .shepherd-empty-state { text-align:center; color:var(--ink2); padding:48px 24px; }
272
382
  .shepherd-empty-state button { margin-top:14px; }
package/dist/preview.js CHANGED
@@ -41,11 +41,26 @@ let tokens = [
41
41
  ];
42
42
  let nextTokenId = 3;
43
43
  let lastInvite = null;
44
- const workspace = { id: "ws_preview", slug: "acme", name: "Acme Engineering", role: "admin" };
44
+ // A small mutable list so the app-bar workspace switcher (switch / create /
45
+ // join) can be clicked through — create/join append here, listWorkspaces reads it.
46
+ let workspaces = [
47
+ { id: "ws_preview", slug: "poop", name: "Poop on a stick", role: "admin" },
48
+ { id: "ws_acme", slug: "acme", name: "Acme Engineering", role: "member" },
49
+ ];
50
+ let nextWsId = 1;
45
51
  const previewClient = {
46
52
  baseUrl: "https://shepherd-hub-preview.a.run.app",
47
- listWorkspaces: async () => ({ workspaces: [workspace] }),
48
- createWorkspace: async (_body) => workspace,
53
+ listWorkspaces: async () => ({ workspaces }),
54
+ createWorkspace: async (body) => {
55
+ const ws = {
56
+ id: `ws_new_${nextWsId++}`,
57
+ slug: "new",
58
+ name: body.name,
59
+ role: "admin",
60
+ };
61
+ workspaces = [...workspaces, ws];
62
+ return ws;
63
+ },
49
64
  mintToken: async (_workspaceId, body) => {
50
65
  const id = `tok_${nextTokenId++}`;
51
66
  tokens = [
@@ -74,7 +89,16 @@ const previewClient = {
74
89
  revokeInvite: async () => {
75
90
  lastInvite = null;
76
91
  },
77
- redeemInvite: async () => ({ workspace }),
92
+ redeemInvite: async () => {
93
+ const joined = {
94
+ id: `ws_joined_${nextWsId++}`,
95
+ slug: "joined",
96
+ name: "Joined workspace",
97
+ role: "member",
98
+ };
99
+ workspaces = [...workspaces, joined];
100
+ return { workspace: joined };
101
+ },
78
102
  listMembers: async () => ({ members }),
79
103
  removeMember: async (_workspaceId, accountId) => {
80
104
  members = members.filter((m) => m.accountId !== accountId);