@korso/shepherd-ui 0.2.1 → 0.3.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-B7nioe5N.js";
3
+ import { c as d, a as m, D as u } from "./Dashboard-Bgi50wCo.js";
4
4
  const i = "shepherd.token";
5
5
  function p() {
6
6
  try {
@@ -12,9 +12,7 @@
12
12
  }
13
13
  .wrap { max-width:1100px; margin:0 auto; padding:40px 44px; }
14
14
 
15
- header { display:flex; align-items:center; gap:12px; padding-bottom:18px; border-bottom:1px solid var(--line); }
16
- /* Chat view: the card supplies its own border, so the header rule is redundant. */
17
- #board:has(#panel-chat:not([hidden])) header { border-bottom:0; }
15
+ header { display:flex; align-items:center; gap:12px; padding-bottom:18px; }
18
16
  .brand { font-size:17px; font-weight:600; }
19
17
  .vitals { color:var(--ink3); font-size:12.5px; }
20
18
  .grow { flex:1; }
@@ -181,37 +179,130 @@
181
179
  .gate button { padding:10px 16px; border-radius:8px; border:1px solid var(--ink);
182
180
  background:var(--ink); color:var(--bg); font-weight:600; cursor:pointer; }
183
181
 
184
- /* --- Multi-workspace hosted shell + config surface (functional, not polished;
185
- a dedicated styling sub-project refines this). Reuses the board's tokens. --- */
182
+ /* --- Multi-workspace hosted shell + config surface. Reuses the board's
183
+ tokens and its editorial vocabulary (uppercase micro-labels echoing the
184
+ column heads, hairline rules) so Config reads as part of the board. --- */
186
185
  .shepherd-root { max-width:1100px; margin:0 auto; padding:40px 44px; }
187
186
  .shepherd-root > main { padding-top:18px; }
188
- .shepherd-config { display:flex; flex-direction:column; gap:24px; }
189
- .shepherd-config h2 { font-size:16px; margin:0 0 4px; }
190
- .shepherd-workspaces, .shepherd-members, .shepherd-connect-agent {
191
- display:flex; flex-direction:column; gap:10px;
192
- padding:16px; border:1px solid var(--line); border-radius:10px; background:var(--card); }
193
- .shepherd-workspaces .switcher { display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
194
- .shepherd-workspaces .role { color:var(--ink3); font-size:12px; }
195
- .shepherd-workspaces .admin, .shepherd-workspaces .invites { display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
196
- /* Create-workspace + join-by-code rows: label, input, then action button on
197
- one line. A fixed-width label column aligns the two rows' inputs vertically. */
198
- .shepherd-workspaces .create, .shepherd-workspaces .join {
199
- display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
200
- .shepherd-workspaces .create > label, .shepherd-workspaces .join > label,
201
- .shepherd-workspaces .switcher > label { min-width:104px; color:var(--ink2); }
202
- .shepherd-workspaces .create > input, .shepherd-workspaces .join > input {
203
- flex:1; min-width:180px; }
187
+ .shepherd-config { display:flex; flex-direction:column; }
188
+ .shepherd-config h2 { font-size:16px; margin:0 0 22px; }
189
+
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); }
195
+ .shepherd-config .card-head h3 {
196
+ font-size:13px; font-weight:600; letter-spacing:.04em; text-transform:uppercase;
197
+ color:var(--ink2); margin:0; }
198
+ .shepherd-config .card-sub { margin:4px 0 0; font-size:12.5px; color:var(--ink3); }
199
+ .shepherd-config .card-head { margin-bottom:16px; }
200
+ .shepherd-config .card-body { display:flex; flex-direction:column; gap:16px; }
201
+ .shepherd-config .card-body > [role="alert"] { margin:0; color:var(--drop); font-size:13px; }
202
+ .shepherd-config .card-body > [role="status"] { margin:0; color:var(--ink2); font-size:13px; }
203
+
204
+ /* A field: uppercase eyebrow label, optional helper, then input(s) + action
205
+ on one row. Labels borrow the board's .colhead h2 treatment. */
206
+ .shepherd-config .field { display:flex; flex-direction:column; gap:8px; }
207
+ .shepherd-config .card-body label {
208
+ font-size:11px; font-weight:600; letter-spacing:.05em; text-transform:uppercase; color:var(--ink3); }
209
+ .shepherd-config .helper { margin:0; font-size:12.5px; color:var(--ink2); }
210
+ .shepherd-config .field > select { width:100%; }
211
+ .shepherd-config select {
212
+ appearance:none; -webkit-appearance:none; -moz-appearance:none;
213
+ background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%239c917a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
214
+ background-repeat:no-repeat; background-position:right 28px center; padding-right:44px; }
215
+ .shepherd-config .field__row { display:flex; gap:10px; align-items:center; flex-wrap:wrap; }
216
+ .shepherd-config .field__row > input { flex:1; min-width:200px; }
217
+
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; }
222
+
204
223
  .shepherd-config input, .shepherd-config select {
205
- padding:8px 10px; border-radius:8px; border:1px solid var(--line);
206
- background:var(--bg); color:var(--ink); }
224
+ padding:9px 12px; border-radius:8px; border:1px solid var(--line);
225
+ background:var(--bg); color:var(--ink); font:inherit;
226
+ transition:border-color .12s ease, box-shadow .12s ease; }
227
+ .shepherd-config input::placeholder { color:var(--ink3); }
228
+ .shepherd-config input:focus, .shepherd-config select:focus {
229
+ outline:none; border-color:var(--terr); box-shadow:0 0 0 3px rgba(122,106,72,.14); }
207
230
  .shepherd-config button {
208
- padding:8px 14px; border-radius:8px; border:1px solid var(--ink);
209
- background:var(--ink); color:var(--bg); font-weight:600; cursor:pointer; }
231
+ padding:9px 16px; border-radius:8px; border:1px solid var(--ink);
232
+ background:var(--ink); color:var(--bg); font-weight:600; cursor:pointer; font:inherit;
233
+ white-space:nowrap; transition:background .12s ease; }
234
+ .shepherd-config button:hover:not(:disabled) { background:#413a2a; }
210
235
  .shepherd-config button:disabled { opacity:.55; cursor:default; }
236
+
237
+ /* Token / member rows: leading name grows, meta + action ride the right.
238
+ Flat rows separated by hairlines (mirrors the board's .claim rows)
239
+ rather than individually boxed items. */
240
+ .shepherd-config ul { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; }
241
+ .shepherd-config li { display:flex; align-items:center; gap:10px; padding:10px 0; font-size:13px; }
242
+ .shepherd-config li + li { border-top:1px solid var(--line2); }
243
+ .shepherd-config li > span:first-child { flex:1; min-width:0; font-weight:500; }
244
+ .shepherd-config li button { padding:5px 12px; }
245
+ .shepherd-config .role { color:var(--ink3); font-size:12px; }
246
+ .shepherd-config .token-meta { color:var(--ink3); font-size:12px; }
247
+ .shepherd-config .email-invite__status { margin:0; font-size:12.5px; color:var(--ink2); }
248
+
249
+ /* Install command block. */
250
+ .shepherd-connect-agent .install-command { position:relative; }
251
+ .shepherd-connect-agent pre { margin:0; padding:12px 14px; border-radius:8px;
252
+ border:1px solid var(--line); background:var(--bg); color:var(--ink);
253
+ font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:12px; line-height:1.5;
254
+ 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); }
260
+ .shepherd-connect-agent h4 { margin:6px 0 0; font-size:11px; font-weight:600;
261
+ letter-spacing:.05em; text-transform:uppercase; color:var(--ink3); }
262
+
211
263
  .shepherd-config .invite-result, .shepherd-connect-agent .token-once {
212
264
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:12px;
213
- word-break:break-all; padding:8px 10px; border-radius:8px;
265
+ padding:10px 12px; border-radius:8px;
214
266
  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); }
215
270
  .shepherd-config .revoked { color:var(--ink3); text-decoration:line-through; }
216
271
  .shepherd-empty-state { text-align:center; color:var(--ink2); padding:48px 24px; }
217
272
  .shepherd-empty-state button { margin-top:14px; }
273
+
274
+ /* Feedback widget: fixed bottom-right, floats over every tab. */
275
+ .shepherd-feedback { position:fixed; right:20px; bottom:20px; z-index:10; }
276
+ .shepherd-feedback__trigger {
277
+ padding:9px 16px; border-radius:999px; border:1px solid var(--ink);
278
+ background:var(--ink); color:var(--bg); font-weight:600; font-size:13px; font:inherit;
279
+ cursor:pointer; box-shadow:0 8px 24px rgba(50,40,20,.18); }
280
+ .shepherd-feedback__trigger:hover { background:#413a2a; }
281
+ .shepherd-feedback__panel {
282
+ position:absolute; right:0; bottom:calc(100% + 10px); width:280px;
283
+ display:flex; flex-direction:column; gap:10px; padding:16px;
284
+ background:var(--card); border:1px solid var(--line); border-radius:12px;
285
+ box-shadow:0 8px 24px rgba(50,40,20,.18); }
286
+ .shepherd-feedback__panel h3 {
287
+ margin:0; font-size:13px; font-weight:600; letter-spacing:.04em;
288
+ text-transform:uppercase; color:var(--ink2); }
289
+ .shepherd-feedback__panel [role="status"] { margin:0; font-size:13px; color:var(--ink2); }
290
+ .shepherd-feedback__panel [role="alert"] { margin:0; font-size:13px; color:var(--drop); }
291
+ .shepherd-feedback__types { display:flex; gap:6px; }
292
+ .shepherd-feedback__types button {
293
+ flex:1; padding:6px 0; border-radius:8px; border:1px solid var(--line);
294
+ background:transparent; color:var(--ink2); font-size:12.5px; font:inherit;
295
+ cursor:pointer; transition:background .12s ease, color .12s ease; }
296
+ .shepherd-feedback__types button[aria-pressed="true"] {
297
+ background:var(--ink); color:var(--bg); border-color:var(--ink); font-weight:600; }
298
+ .shepherd-feedback__panel textarea {
299
+ min-height:80px; padding:9px 12px; border-radius:8px; border:1px solid var(--line);
300
+ background:var(--bg); color:var(--ink); font:inherit; resize:vertical; }
301
+ .shepherd-feedback__panel textarea::placeholder { color:var(--ink3); }
302
+ .shepherd-feedback__panel textarea:focus {
303
+ outline:none; border-color:var(--terr); box-shadow:0 0 0 3px rgba(122,106,72,.14); }
304
+ .shepherd-feedback__panel > button {
305
+ padding:9px 16px; border-radius:8px; border:1px solid var(--ink);
306
+ background:var(--ink); color:var(--bg); font-weight:600; cursor:pointer; font:inherit; }
307
+ .shepherd-feedback__panel > button:hover:not(:disabled) { background:#413a2a; }
308
+ .shepherd-feedback__panel > button:disabled { opacity:.55; cursor:default; }
@@ -0,0 +1 @@
1
+ import "./styles.css";
@@ -0,0 +1,89 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { StrictMode } from "react";
3
+ import { createRoot } from "react-dom/client";
4
+ import "./styles.css";
5
+ import { ShepherdClientProvider } from "./context.js";
6
+ import { ShepherdRoot } from "./ShepherdRoot.js";
7
+ // ---------------------------------------------------------------------------
8
+ // Dev-only visual preview of the Config surface. NOT part of the published
9
+ // library or the self-host build (vite.config.app.ts's build:app only bundles
10
+ // index.html) — `npm run dev` serves this alongside it at /preview.html. Backs
11
+ // every ShepherdClient method with in-memory state instead of a real Hub, so
12
+ // the redesign can be clicked through without Postgres or a minted token.
13
+ // ---------------------------------------------------------------------------
14
+ const EMPTY_LANDSCAPE = {
15
+ agents: [],
16
+ tasks: [],
17
+ announcements: [],
18
+ serverTime: new Date().toISOString(),
19
+ };
20
+ const EMPTY_ANNOUNCE = { ok: true, announcementIds: [] };
21
+ let members = [
22
+ { accountId: "acc_admin", displayName: "Korso Admin", githubLogin: "korso-admin", avatarUrl: null, role: "admin" },
23
+ { accountId: "acc_1", displayName: "Alex Rivera", githubLogin: "arivera", avatarUrl: null, role: "member" },
24
+ { accountId: "acc_2", displayName: "Sam Okafor", githubLogin: "sokafor", avatarUrl: null, role: "member" },
25
+ ];
26
+ let tokens = [
27
+ {
28
+ id: "tok_1",
29
+ name: "laptop",
30
+ createdAt: "2026-06-01T00:00:00.000Z",
31
+ lastUsedAt: "2026-06-29T10:00:00.000Z",
32
+ revokedAt: null,
33
+ },
34
+ {
35
+ id: "tok_2",
36
+ name: null,
37
+ createdAt: "2026-06-20T00:00:00.000Z",
38
+ lastUsedAt: null,
39
+ revokedAt: null,
40
+ },
41
+ ];
42
+ let nextTokenId = 3;
43
+ let lastInvite = null;
44
+ const workspace = { id: "ws_preview", slug: "acme", name: "Acme Engineering", role: "admin" };
45
+ const previewClient = {
46
+ baseUrl: "https://shepherd-hub-preview.a.run.app",
47
+ listWorkspaces: async () => ({ workspaces: [workspace] }),
48
+ createWorkspace: async (_body) => workspace,
49
+ mintToken: async (_workspaceId, body) => {
50
+ const id = `tok_${nextTokenId++}`;
51
+ tokens = [
52
+ ...tokens,
53
+ { id, name: body.name ?? null, createdAt: new Date().toISOString(), lastUsedAt: null, revokedAt: null },
54
+ ];
55
+ return { token: `shp_previewtoken${id}`, id };
56
+ },
57
+ listTokens: async () => ({ tokens }),
58
+ revokeToken: async (_workspaceId, tokenId) => {
59
+ tokens = tokens.map((t) => (t.id === tokenId ? { ...t, revokedAt: new Date().toISOString() } : t));
60
+ },
61
+ createInvite: async (_workspaceId, body) => {
62
+ lastInvite = {
63
+ code: "PREVIEW-CODE",
64
+ expiresAt: null,
65
+ maxUses: body.maxUses ?? null,
66
+ useCount: 0,
67
+ };
68
+ return lastInvite;
69
+ },
70
+ inviteByEmail: async (_workspaceId, email) => ({
71
+ email,
72
+ sentAt: new Date().toISOString(),
73
+ }),
74
+ revokeInvite: async () => {
75
+ lastInvite = null;
76
+ },
77
+ redeemInvite: async () => ({ workspace }),
78
+ listMembers: async () => ({ members }),
79
+ removeMember: async (_workspaceId, accountId) => {
80
+ members = members.filter((m) => m.accountId !== accountId);
81
+ },
82
+ leave: async () => { },
83
+ landscape: async () => EMPTY_LANDSCAPE,
84
+ announceTo: async (_workspaceId, _body) => EMPTY_ANNOUNCE,
85
+ getLandscape: async () => EMPTY_LANDSCAPE,
86
+ announce: async (_body) => EMPTY_ANNOUNCE,
87
+ submitFeedback: async () => ({ ok: true, id: "fb_preview" }),
88
+ };
89
+ createRoot(document.getElementById("root")).render(_jsx(StrictMode, { children: _jsx(ShepherdClientProvider, { client: previewClient, children: _jsx(ShepherdRoot, { hubUrl: "https://shepherd-hub-preview.a.run.app" }) }) }));