@powerhousedao/builder-team-admin 0.0.3 → 0.0.4

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 +1 @@
1
- {"version":3,"file":"ProfileHeader.d.ts","sourceRoot":"","sources":["../../../../../editors/builder-team-admin/components/overview/ProfileHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gEAAgE,CAAC;AAE7G,KAAK,kBAAkB,GAAG;IACxB,iBAAiB,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAClD,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,iBAAiB,EAAE,EAAE,kBAAkB,kDA2DtE"}
1
+ {"version":3,"file":"ProfileHeader.d.ts","sourceRoot":"","sources":["../../../../../editors/builder-team-admin/components/overview/ProfileHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gEAAgE,CAAC;AAE7G,KAAK,kBAAkB,GAAG;IACxB,iBAAiB,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAClD,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,iBAAiB,EAAE,EAAE,kBAAkB,kDAuDtE"}
@@ -14,11 +14,11 @@ export function ProfileHeader({ builderProfileDoc }) {
14
14
  .join("")
15
15
  .slice(0, 2)
16
16
  .toUpperCase();
17
- return (_jsxs("div", { className: "relative overflow-hidden rounded-2xl bg-gradient-to-br from-slate-50 via-indigo-50/40 to-blue-50/30 p-8 border border-slate-200/60", children: [_jsx("div", { className: "absolute -right-16 -top-16 h-48 w-48 rounded-full bg-gradient-to-br from-indigo-200/30 to-blue-200/30 blur-2xl" }), _jsx("div", { className: "absolute -bottom-12 -left-12 h-32 w-32 rounded-full bg-gradient-to-br from-slate-200/40 to-indigo-200/30 blur-xl" }), _jsxs("div", { className: "relative z-10 flex items-center gap-6", children: [_jsxs("div", { className: "relative", children: [icon ? (_jsx("img", { src: icon, alt: displayName, className: "h-20 w-20 rounded-2xl object-cover shadow-lg shadow-slate-300/50 ring-4 ring-white/80", onError: (e) => {
18
- e.currentTarget.style.display = "none";
19
- const fallback = e.currentTarget.nextElementSibling;
20
- if (fallback) {
21
- fallback.style.display = "flex";
22
- }
23
- } })) : null, _jsx("div", { className: `h-20 w-20 rounded-2xl bg-gradient-to-br from-indigo-500 to-blue-600 shadow-lg shadow-indigo-400/30 ring-4 ring-white/80 ${icon ? "hidden" : "flex"} items-center justify-center`, children: _jsx("span", { className: "text-2xl font-bold text-white", children: initials }) })] }), _jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-bold tracking-tight text-slate-900", children: displayName }), slug && (_jsxs("p", { className: "mt-1 text-base font-medium text-slate-500", children: ["@", slug] }))] })] })] }));
17
+ return (_jsx("div", { className: "overflow-hidden rounded-2xl bg-gradient-to-br from-slate-50 via-indigo-50/40 to-blue-50/30 p-8 border border-slate-200/60", children: _jsxs("div", { className: "flex items-center gap-6", children: [_jsxs("div", { className: "relative", children: [icon ? (_jsx("img", { src: icon, alt: displayName, className: "h-20 w-20 rounded-2xl object-cover shadow-lg shadow-slate-300/50 ring-4 ring-white/80", onError: (e) => {
18
+ e.currentTarget.style.display = "none";
19
+ const fallback = e.currentTarget.nextElementSibling;
20
+ if (fallback) {
21
+ fallback.style.display = "flex";
22
+ }
23
+ } })) : null, _jsx("div", { className: `h-20 w-20 rounded-2xl bg-gradient-to-br from-indigo-500 to-blue-600 shadow-lg shadow-indigo-400/30 ring-4 ring-white/80 ${icon ? "hidden" : "flex"} items-center justify-center`, children: _jsx("span", { className: "text-2xl font-bold text-white", children: initials }) })] }), _jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-bold tracking-tight text-slate-900", children: displayName }), slug && (_jsxs("p", { className: "mt-1 text-base font-medium text-slate-500", children: ["@", slug] }))] })] }) }));
24
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TeamMembersOverview.d.ts","sourceRoot":"","sources":["../../../../../editors/builder-team-admin/components/overview/TeamMembersOverview.tsx"],"names":[],"mappings":"AAWA,KAAK,wBAAwB,GAAG;IAC9B,YAAY,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CACpC,CAAC;AAIF;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,YAAY,GACb,EAAE,wBAAwB,2CAwF1B"}
1
+ {"version":3,"file":"TeamMembersOverview.d.ts","sourceRoot":"","sources":["../../../../../editors/builder-team-admin/components/overview/TeamMembersOverview.tsx"],"names":[],"mappings":"AAYA,KAAK,wBAAwB,GAAG;IAC9B,YAAY,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CACpC,CAAC;AAIF;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,YAAY,GACb,EAAE,wBAAwB,2CAqH1B"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useMemo, useCallback } from "react";
2
+ import { useMemo, useCallback, useState } from "react";
3
3
  import { useDrives, useGetDocuments } from "@powerhousedao/reactor-browser";
4
+ import { useRemoteBuilderProfiles } from "../../hooks/useRemoteBuilderProfiles.js";
4
5
  const MAX_VISIBLE_MEMBERS = 6;
5
6
  /**
6
7
  * Displays team members as a horizontal row of avatar cards.
@@ -28,8 +29,8 @@ export function TeamMembersOverview({ contributors, }) {
28
29
  }, [builderProfileNodesWithDriveId]);
29
30
  // Fetch all builder profile documents from all drives
30
31
  const builderProfileDocuments = useGetDocuments(builderPhids);
31
- // Create a map of PHID to document for quick lookup
32
- const builderProfileMap = useMemo(() => {
32
+ // Create a map of PHID to document for quick lookup (local drives)
33
+ const localBuilderProfileMap = useMemo(() => {
33
34
  const map = new Map();
34
35
  for (const doc of builderProfileDocuments) {
35
36
  if (doc.header.documentType === "powerhouse/builder-profile") {
@@ -38,17 +39,30 @@ export function TeamMembersOverview({ contributors, }) {
38
39
  }
39
40
  return map;
40
41
  }, [builderProfileDocuments]);
41
- // Helper function to get builder profile data by PHID
42
+ // Fetch remote profiles as fallback for contributors not found locally
43
+ const { profileMap: remoteProfileMap } = useRemoteBuilderProfiles(localBuilderProfileMap);
44
+ // Helper function to get builder profile data by PHID (local first, then remote fallback)
42
45
  const getBuilderProfileByPhid = useCallback((phid) => {
43
- const doc = builderProfileMap.get(phid);
44
- if (!doc)
45
- return null;
46
- return {
47
- phid,
48
- name: doc.state.global.name || "Unknown",
49
- icon: doc.state.global.icon || null,
50
- };
51
- }, [builderProfileMap]);
46
+ // Try local first
47
+ const localDoc = localBuilderProfileMap.get(phid);
48
+ if (localDoc) {
49
+ return {
50
+ phid,
51
+ name: localDoc.state.global.name || "Unknown",
52
+ icon: localDoc.state.global.icon || null,
53
+ };
54
+ }
55
+ // Fall back to remote
56
+ const remoteProfile = remoteProfileMap.get(phid);
57
+ if (remoteProfile) {
58
+ return {
59
+ phid,
60
+ name: remoteProfile.state?.name || "Unknown",
61
+ icon: remoteProfile.state?.icon || null,
62
+ };
63
+ }
64
+ return null;
65
+ }, [localBuilderProfileMap, remoteProfileMap]);
52
66
  // Map contributors to team member data
53
67
  const teamMembers = useMemo(() => {
54
68
  if (!contributors)
@@ -58,12 +72,16 @@ export function TeamMembersOverview({ contributors, }) {
58
72
  .filter((member) => member !== null);
59
73
  }, [contributors, getBuilderProfileByPhid]);
60
74
  const contributorCount = contributors?.length ?? 0;
75
+ const [isExpanded, setIsExpanded] = useState(false);
61
76
  if (contributorCount === 0) {
62
77
  return _jsx(TeamMembersEmptyState, {});
63
78
  }
64
- const visibleMembers = teamMembers.slice(0, MAX_VISIBLE_MEMBERS);
79
+ const hasOverflow = contributorCount > MAX_VISIBLE_MEMBERS;
80
+ const visibleMembers = isExpanded
81
+ ? teamMembers
82
+ : teamMembers.slice(0, MAX_VISIBLE_MEMBERS);
65
83
  const overflowCount = contributorCount - MAX_VISIBLE_MEMBERS;
66
- return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("h2", { className: "text-lg font-semibold text-slate-900", children: "Team Members" }), _jsx("span", { className: "inline-flex items-center justify-center rounded-full bg-indigo-100 px-2.5 py-0.5 text-sm font-medium text-indigo-700", children: contributorCount })] }), _jsxs("div", { className: "flex flex-wrap gap-4", children: [visibleMembers.map((member) => (_jsx(MemberCard, { member: member }, member.phid))), overflowCount > 0 && _jsx(OverflowIndicator, { count: overflowCount })] })] }));
84
+ return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("h2", { className: "text-lg font-semibold text-slate-900", children: "Team Members" }), _jsx("span", { className: "inline-flex items-center justify-center rounded-full bg-indigo-100 px-2.5 py-0.5 text-sm font-medium text-indigo-700", children: contributorCount })] }), _jsxs("div", { className: "flex flex-wrap gap-4", children: [visibleMembers.map((member) => (_jsx(MemberCard, { member: member }, member.phid))), hasOverflow && !isExpanded && (_jsx(OverflowIndicator, { count: overflowCount, onClick: () => setIsExpanded(true) })), hasOverflow && isExpanded && (_jsx(CollapseIndicator, { onClick: () => setIsExpanded(false) }))] })] }));
67
85
  }
68
86
  /**
69
87
  * Individual team member card with avatar and name.
@@ -84,10 +102,16 @@ function MemberCard({ member }) {
84
102
  } })) : null, _jsx("div", { className: `h-14 w-14 rounded-full bg-gradient-to-br from-slate-400 to-slate-500 ring-2 ring-white shadow-md ${member.icon ? "hidden" : "flex"} items-center justify-center transition-transform group-hover:scale-105`, children: _jsx("span", { className: "text-sm font-semibold text-white", children: initials }) })] }), _jsx("span", { className: "max-w-[80px] truncate text-xs font-medium text-slate-600", children: member.name })] }));
85
103
  }
86
104
  /**
87
- * Overflow indicator showing remaining member count.
105
+ * Overflow indicator showing remaining member count. Clickable to expand.
106
+ */
107
+ function OverflowIndicator({ count, onClick, }) {
108
+ return (_jsxs("button", { type: "button", onClick: onClick, className: "flex flex-col items-center gap-2 group cursor-pointer", title: "Click to show all members", children: [_jsx("div", { className: "flex h-14 w-14 items-center justify-center rounded-full bg-slate-100 ring-2 ring-white shadow-sm transition-all group-hover:bg-indigo-100 group-hover:ring-indigo-200", children: _jsxs("span", { className: "text-sm font-semibold text-slate-500 group-hover:text-indigo-600", children: ["+", count] }) }), _jsx("span", { className: "text-xs font-medium text-slate-400 group-hover:text-indigo-500", children: "show all" })] }));
109
+ }
110
+ /**
111
+ * Collapse indicator to hide extra members. Clickable to collapse.
88
112
  */
89
- function OverflowIndicator({ count }) {
90
- return (_jsxs("div", { className: "flex flex-col items-center gap-2", children: [_jsx("div", { className: "flex h-14 w-14 items-center justify-center rounded-full bg-slate-100 ring-2 ring-white shadow-sm", children: _jsxs("span", { className: "text-sm font-semibold text-slate-500", children: ["+", count] }) }), _jsx("span", { className: "text-xs font-medium text-slate-400", children: "more" })] }));
113
+ function CollapseIndicator({ onClick }) {
114
+ return (_jsxs("button", { type: "button", onClick: onClick, className: "flex flex-col items-center gap-2 group cursor-pointer", title: "Click to show less", children: [_jsx("div", { className: "flex h-14 w-14 items-center justify-center rounded-full bg-slate-100 ring-2 ring-white shadow-sm transition-all group-hover:bg-slate-200", children: _jsx("svg", { className: "h-5 w-5 text-slate-500 group-hover:text-slate-700", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 15l7-7 7 7" }) }) }), _jsx("span", { className: "text-xs font-medium text-slate-400 group-hover:text-slate-600", children: "show less" })] }));
91
115
  }
92
116
  /**
93
117
  * Empty state when no team members have been added.
@@ -1 +1 @@
1
- {"version":3,"file":"team-members.d.ts","sourceRoot":"","sources":["../../../../editors/builder-team-admin/components/team-members.tsx"],"names":[],"mappings":"AAkCA,wBAAgB,mBAAmB,CAAC,EAAE,IAAA,2CAwRrC"}
1
+ {"version":3,"file":"team-members.d.ts","sourceRoot":"","sources":["../../../../editors/builder-team-admin/components/team-members.tsx"],"names":[],"mappings":"AAmKA,wBAAgB,mBAAmB,CAAC,EAAE,IAAA,2CA0TrC"}
@@ -1,8 +1,90 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useMemo, useCallback } from "react";
2
+ import { useMemo, useCallback, useState, useEffect } from "react";
3
3
  import { useDocumentsInSelectedDrive, useDrives, useGetDocuments, useDocumentById, } from "@powerhousedao/reactor-browser";
4
4
  import { ObjectSetTable, PHIDInput, } from "@powerhousedao/document-engineering";
5
5
  import { actions as builderProfileActions } from "@powerhousedao/builder-profile/document-models/builder-profile";
6
+ import { useRemoteBuilderProfiles } from "../hooks/useRemoteBuilderProfiles.js";
7
+ /**
8
+ * Wrapper component for PHIDInput that properly tracks selected PHID
9
+ * and handles saving on blur/enter with the correct PHID value.
10
+ *
11
+ * Key insight from the PHIDInput library:
12
+ * - onChange is called with the PHID value when user selects from dropdown (click or Enter on highlighted item)
13
+ * - After dropdown selection, the input is re-focused so onBlur doesn't fire
14
+ * - Therefore we must save immediately in onChange when a valid PHID is selected
15
+ */
16
+ function ContributorPHIDInput({ initialPhid, options, onSave, fetchOptionsCallback, }) {
17
+ // Track the current input text for manual entry lookup
18
+ const [inputText, setInputText] = useState("");
19
+ // Track if we already saved to prevent duplicate saves
20
+ const [hasSaved, setHasSaved] = useState(false);
21
+ // Reset state when initialPhid changes (switching between rows)
22
+ useEffect(() => {
23
+ setInputText("");
24
+ setHasSaved(false);
25
+ }, [initialPhid]);
26
+ // Find PHID by name or return the input if it looks like a PHID
27
+ const findPhidByInput = useCallback((input) => {
28
+ const trimmed = input.trim();
29
+ if (!trimmed)
30
+ return null;
31
+ const lowerInput = trimmed.toLowerCase();
32
+ // Check if input matches a profile name exactly (case-insensitive)
33
+ const exactMatchByName = options.find((opt) => opt.label.toLowerCase() === lowerInput);
34
+ if (exactMatchByName)
35
+ return exactMatchByName.id;
36
+ // Check if input matches a profile name partially (first match that starts with input)
37
+ const partialMatchByName = options.find((opt) => opt.label.toLowerCase().startsWith(lowerInput));
38
+ if (partialMatchByName)
39
+ return partialMatchByName.id;
40
+ // Check if only one option contains the input (unambiguous match)
41
+ const containsMatches = options.filter((opt) => opt.label.toLowerCase().includes(lowerInput));
42
+ if (containsMatches.length === 1)
43
+ return containsMatches[0].id;
44
+ // Check if input matches a profile ID
45
+ const matchById = options.find((opt) => opt.id.toLowerCase() === lowerInput);
46
+ if (matchById)
47
+ return matchById.id;
48
+ // If input looks like a UUID, return it directly
49
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
50
+ if (uuidRegex.test(trimmed))
51
+ return trimmed;
52
+ return null;
53
+ }, [options]);
54
+ // Check if a value is a known PHID from options
55
+ const isKnownPhid = useCallback((value) => {
56
+ return options.some((opt) => opt.id === value);
57
+ }, [options]);
58
+ // Save a PHID value (with duplicate prevention)
59
+ const savePhid = useCallback((phid) => {
60
+ if (!hasSaved && phid && phid !== initialPhid) {
61
+ setHasSaved(true);
62
+ onSave(phid);
63
+ }
64
+ }, [hasSaved, initialPhid, onSave]);
65
+ // Handle blur - try to save based on inputText
66
+ const handleBlur = useCallback(() => {
67
+ if (hasSaved)
68
+ return;
69
+ if (inputText) {
70
+ const foundPhid = findPhidByInput(inputText);
71
+ if (foundPhid) {
72
+ savePhid(foundPhid);
73
+ }
74
+ }
75
+ }, [hasSaved, inputText, findPhidByInput, savePhid]);
76
+ return (_jsx(PHIDInput, { value: initialPhid, onChange: (newValue) => {
77
+ // onChange is called when user selects from dropdown (click or Enter on highlighted item)
78
+ // The newValue is the PHID. Save immediately if it's a valid known PHID.
79
+ if (isKnownPhid(newValue)) {
80
+ savePhid(newValue);
81
+ }
82
+ }, onInput: (e) => {
83
+ // Track the raw input text for manual entry lookup on blur
84
+ const target = e.target;
85
+ setInputText(target.value);
86
+ }, onBlur: handleBlur, placeholder: "Enter PHID or search by name", className: "w-full", variant: "withValueAndTitle", initialOptions: options, fetchOptionsCallback: fetchOptionsCallback }));
87
+ }
6
88
  export function ContributorsSection({}) {
7
89
  const drives = useDrives();
8
90
  const documentsInSelectedDrive = useDocumentsInSelectedDrive();
@@ -37,8 +119,8 @@ export function ContributorsSection({}) {
37
119
  }, [builderProfileNodesWithDriveId]);
38
120
  // Fetch all builder profile documents from all drives
39
121
  const builderProfileDocuments = useGetDocuments(builderPhids);
40
- // Create a map of PHID to document for quick lookup
41
- const builderProfileMap = useMemo(() => {
122
+ // Create a map of PHID to document for quick lookup (local drives)
123
+ const localBuilderProfileMap = useMemo(() => {
42
124
  const map = new Map();
43
125
  if (!builderProfileDocuments)
44
126
  return map;
@@ -49,10 +131,13 @@ export function ContributorsSection({}) {
49
131
  });
50
132
  return map;
51
133
  }, [builderProfileDocuments]);
52
- // Helper function to get builder profile documents from all drives
134
+ // Fetch remote profiles as fallback for contributors not found locally
135
+ const { profileMap: remoteProfileMap, allProfiles: remoteProfiles } = useRemoteBuilderProfiles(localBuilderProfileMap);
136
+ // Helper function to get builder profile documents from all drives (local + remote)
53
137
  const getBuilderProfiles = useCallback(() => {
54
- return builderProfileNodesWithDriveId.map(({ node }) => {
55
- const doc = builderProfileMap.get(node.id);
138
+ // Start with local profiles
139
+ const profileOptions = builderProfileNodesWithDriveId.map(({ node }) => {
140
+ const doc = localBuilderProfileMap.get(node.id);
56
141
  const name = doc?.state?.global?.name || node.name || node.id;
57
142
  return {
58
143
  id: node.id,
@@ -61,18 +146,43 @@ export function ContributorsSection({}) {
61
146
  title: name,
62
147
  };
63
148
  });
64
- }, [builderProfileNodesWithDriveId, builderProfileMap]);
65
- // Helper function to get builder profile data by PHID from all drives
149
+ // Add remote profiles that aren't already in local
150
+ const localIds = new Set(profileOptions.map((p) => p.id));
151
+ for (const remoteProfile of remoteProfiles) {
152
+ if (!localIds.has(remoteProfile.id)) {
153
+ const name = remoteProfile.state?.name || remoteProfile.id;
154
+ profileOptions.push({
155
+ id: remoteProfile.id,
156
+ label: name,
157
+ value: remoteProfile.id,
158
+ title: name,
159
+ });
160
+ }
161
+ }
162
+ return profileOptions;
163
+ }, [builderProfileNodesWithDriveId, localBuilderProfileMap, remoteProfiles]);
164
+ // Helper function to get builder profile data by PHID (local first, then remote fallback)
66
165
  const getBuilderProfileByPhid = useCallback((phid) => {
67
- const doc = builderProfileMap.get(phid);
68
- if (!doc)
69
- return null;
70
- return {
71
- name: doc.state.global?.name || doc.header.id,
72
- slug: doc.state.global?.slug || doc.header.id,
73
- icon: doc.state.global?.icon || null,
74
- };
75
- }, [builderProfileMap]);
166
+ // Try local first
167
+ const localDoc = localBuilderProfileMap.get(phid);
168
+ if (localDoc) {
169
+ return {
170
+ name: localDoc.state.global?.name || localDoc.header.id,
171
+ slug: localDoc.state.global?.slug || localDoc.header.id,
172
+ icon: localDoc.state.global?.icon || null,
173
+ };
174
+ }
175
+ // Fall back to remote
176
+ const remoteProfile = remoteProfileMap.get(phid);
177
+ if (remoteProfile) {
178
+ return {
179
+ name: remoteProfile.state?.name || remoteProfile.id,
180
+ slug: remoteProfile.state?.slug || remoteProfile.id,
181
+ icon: remoteProfile.state?.icon || null,
182
+ };
183
+ }
184
+ return null;
185
+ }, [localBuilderProfileMap, remoteProfileMap]);
76
186
  const contributorData = useMemo(() => {
77
187
  return contributors.map((phid) => {
78
188
  const profile = getBuilderProfileByPhid(phid);
@@ -106,39 +216,38 @@ export function ContributorsSection({}) {
106
216
  }
107
217
  return false;
108
218
  },
109
- renderCellEditor: (value, onChange, context) => (_jsx(PHIDInput, { value: value || "", onChange: (newValue) => {
110
- onChange(newValue);
111
- }, onBlur: (e) => {
112
- const newValue = e.target.value;
113
- const currentValue = value || "";
219
+ renderCellEditor: (_value, _onChange, context) => {
220
+ const currentPhid = context.row.phid || "";
221
+ const handleSave = (phidValue) => {
114
222
  // If a PHID is entered and it's different from current value
115
- if (newValue && newValue !== currentValue) {
116
- const existingContributor = contributors.find((contributor) => contributor === newValue);
223
+ if (phidValue && phidValue !== currentPhid) {
224
+ const existingContributor = contributors.find((contributor) => contributor === phidValue);
117
225
  if (!existingContributor) {
118
226
  // If we're editing an existing row (has an ID), remove the old one first
119
- if (context.row.phid && context.row.phid !== newValue) {
227
+ if (currentPhid && currentPhid !== phidValue) {
120
228
  dispatch(builderProfileActions.removeContributor({
121
- contributorPHID: context.row.phid,
229
+ contributorPHID: currentPhid,
122
230
  }));
123
231
  }
124
232
  // Add the new contributor
125
233
  dispatch(builderProfileActions.addContributor({
126
- contributorPHID: newValue,
234
+ contributorPHID: phidValue,
127
235
  }));
128
236
  }
129
237
  }
130
- }, placeholder: "Enter PHID", className: "w-full", variant: "withValueAndTitle", initialOptions: getBuilderProfiles(), fetchOptionsCallback: (userInput) => {
238
+ };
239
+ const fetchOptions = (userInput) => {
131
240
  const builderProfiles = getBuilderProfiles();
132
241
  // Filter profiles based on user input
133
242
  if (!userInput.trim()) {
134
243
  return Promise.resolve(builderProfiles);
135
244
  }
136
- const filteredProfiles = builderProfiles.filter((profile) => profile.label
137
- .toLowerCase()
138
- .includes(userInput.toLowerCase()) ||
245
+ const filteredProfiles = builderProfiles.filter((profile) => profile.label.toLowerCase().includes(userInput.toLowerCase()) ||
139
246
  profile.id.toLowerCase().includes(userInput.toLowerCase()));
140
247
  return Promise.resolve(filteredProfiles);
141
- } })),
248
+ };
249
+ return (_jsx(ContributorPHIDInput, { initialPhid: currentPhid, options: getBuilderProfiles(), onSave: handleSave, fetchOptionsCallback: fetchOptions }, `phid-input-${currentPhid || Date.now()}`));
250
+ },
142
251
  renderCell: (value) => {
143
252
  if (value === "" || !value) {
144
253
  return (_jsx("div", { className: "font-light italic text-gray-500 text-center", children: "+ Double-click to add new contributor (enter or click outside to save)" }));
@@ -0,0 +1,20 @@
1
+ import { type RemoteBuilderProfile } from "../utils/graphql-client.js";
2
+ interface UseRemoteBuilderProfilesResult {
3
+ /** Map of PHID to remote builder profile data */
4
+ profileMap: Map<string, RemoteBuilderProfile>;
5
+ /** All available remote profiles for selection */
6
+ allProfiles: RemoteBuilderProfile[];
7
+ /** Whether remote data is currently loading */
8
+ isLoading: boolean;
9
+ /** Manually refetch all available profiles */
10
+ refetchAll: () => Promise<void>;
11
+ }
12
+ /**
13
+ * Hook for fetching builder profiles from remote Switchboard drives.
14
+ * Used as a fallback when local drives don't have the builder profile documents.
15
+ *
16
+ * @param localProfileMap - Map of PHIDs that are already resolved locally (to avoid using remote data for those)
17
+ */
18
+ export declare function useRemoteBuilderProfiles(localProfileMap: Map<string, unknown>): UseRemoteBuilderProfilesResult;
19
+ export {};
20
+ //# sourceMappingURL=useRemoteBuilderProfiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRemoteBuilderProfiles.d.ts","sourceRoot":"","sources":["../../../../editors/builder-team-admin/hooks/useRemoteBuilderProfiles.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,4BAA4B,CAAC;AAEpC,UAAU,8BAA8B;IACtC,iDAAiD;IACjD,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAC9C,kDAAkD;IAClD,WAAW,EAAE,oBAAoB,EAAE,CAAC;IACpC,+CAA+C;IAC/C,SAAS,EAAE,OAAO,CAAC;IACnB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GACpC,8BAA8B,CA8DhC"}
@@ -0,0 +1,57 @@
1
+ import { useState, useEffect, useCallback, useRef } from "react";
2
+ import { fetchAllRemoteBuilderProfiles, } from "../utils/graphql-client.js";
3
+ /**
4
+ * Hook for fetching builder profiles from remote Switchboard drives.
5
+ * Used as a fallback when local drives don't have the builder profile documents.
6
+ *
7
+ * @param localProfileMap - Map of PHIDs that are already resolved locally (to avoid using remote data for those)
8
+ */
9
+ export function useRemoteBuilderProfiles(localProfileMap) {
10
+ const [profileMap, setProfileMap] = useState(new Map());
11
+ const [allProfiles, setAllProfiles] = useState([]);
12
+ const [isLoading, setIsLoading] = useState(false);
13
+ // Track if we've already started fetching to avoid duplicate requests
14
+ const isFetchingRef = useRef(false);
15
+ const hasFetchedRef = useRef(false);
16
+ // Fetch all available profiles
17
+ const refetchAll = useCallback(async () => {
18
+ // Prevent concurrent fetches
19
+ if (isFetchingRef.current) {
20
+ return;
21
+ }
22
+ isFetchingRef.current = true;
23
+ setIsLoading(true);
24
+ try {
25
+ const profiles = await fetchAllRemoteBuilderProfiles();
26
+ hasFetchedRef.current = true;
27
+ setAllProfiles(profiles);
28
+ // Build profile map
29
+ const newMap = new Map();
30
+ profiles.forEach((profile) => {
31
+ newMap.set(profile.id, profile);
32
+ });
33
+ setProfileMap(newMap);
34
+ }
35
+ catch (error) {
36
+ console.warn("[useRemoteBuilderProfiles] Failed to fetch profiles:", error);
37
+ }
38
+ finally {
39
+ setIsLoading(false);
40
+ isFetchingRef.current = false;
41
+ }
42
+ }, []);
43
+ // Auto-fetch all profiles on mount
44
+ useEffect(() => {
45
+ if (!hasFetchedRef.current && !isFetchingRef.current) {
46
+ void refetchAll();
47
+ }
48
+ }, [refetchAll]);
49
+ // Filter out profiles that exist locally from the returned allProfiles
50
+ const filteredAllProfiles = allProfiles.filter((profile) => !localProfileMap.has(profile.id));
51
+ return {
52
+ profileMap,
53
+ allProfiles: filteredAllProfiles,
54
+ isLoading,
55
+ refetchAll,
56
+ };
57
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * GraphQL client utility for fetching remote builder profiles from Switchboard.
3
+ * This is used as a fallback when local drives don't have the builder profile documents.
4
+ */
5
+ export interface RemoteBuilderProfile {
6
+ id: string;
7
+ state: {
8
+ name: string | null;
9
+ slug: string | null;
10
+ icon: string | null;
11
+ };
12
+ }
13
+ /**
14
+ * Fetches all available remote drives
15
+ */
16
+ export declare function fetchRemoteDrives(): Promise<string[]>;
17
+ /**
18
+ * Fetches drive ID by slug
19
+ */
20
+ export declare function fetchDriveIdBySlug(slug: string): Promise<string | null>;
21
+ /**
22
+ * Fetches all builder profiles from a specific drive
23
+ */
24
+ export declare function fetchBuilderProfilesFromDrive(driveId: string, options?: {
25
+ silent?: boolean;
26
+ }): Promise<RemoteBuilderProfile[]>;
27
+ /**
28
+ * Fetches a single builder profile by document ID
29
+ */
30
+ export declare function fetchBuilderProfileById(docId: string, driveId?: string): Promise<RemoteBuilderProfile | null>;
31
+ /**
32
+ * Fetches all builder profiles from all available remote drives.
33
+ * This aggregates profiles from multiple drives into a single list.
34
+ */
35
+ export declare function fetchAllRemoteBuilderProfiles(): Promise<RemoteBuilderProfile[]>;
36
+ /**
37
+ * Fetches multiple builder profiles by their IDs.
38
+ * Tries to find them across all available remote drives.
39
+ */
40
+ export declare function fetchRemoteBuilderProfilesByIds(phids: string[]): Promise<Map<string, RemoteBuilderProfile>>;
41
+ //# sourceMappingURL=graphql-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphql-client.d.ts","sourceRoot":"","sources":["../../../../editors/builder-team-admin/utils/graphql-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuHH,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;KACrB,CAAC;CACH;AAcD;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAG3D;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAM7E;AAED;;GAEG;AACH,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAOjC;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAMtC;AAED;;;GAGG;AACH,wBAAsB,6BAA6B,IAAI,OAAO,CAC5D,oBAAoB,EAAE,CACvB,CA8BA;AAED;;;GAGG;AACH,wBAAsB,+BAA+B,CACnD,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAiC5C"}
@@ -0,0 +1,180 @@
1
+ /**
2
+ * GraphQL client utility for fetching remote builder profiles from Switchboard.
3
+ * This is used as a fallback when local drives don't have the builder profile documents.
4
+ */
5
+ function getGraphQLUrl() {
6
+ if (typeof window === "undefined") {
7
+ return "http://localhost:4001/graphql";
8
+ }
9
+ if (!window.document.baseURI.includes("localhost")) {
10
+ return window.document.baseURI + "/graphql";
11
+ }
12
+ return "http://localhost:4001/graphql";
13
+ }
14
+ async function graphqlRequest(query, variables, options) {
15
+ try {
16
+ const response = await fetch(getGraphQLUrl(), {
17
+ method: "POST",
18
+ headers: {
19
+ "Content-Type": "application/json",
20
+ },
21
+ body: JSON.stringify({ query, variables }),
22
+ });
23
+ if (!response.ok) {
24
+ if (!options?.silent) {
25
+ console.warn("[graphql-client] Request failed:", response.status, response.statusText);
26
+ }
27
+ return null;
28
+ }
29
+ const result = (await response.json());
30
+ // Return data even if there are errors - partial data might still be useful
31
+ // Only treat as full failure if there's no data at all
32
+ if (result.errors?.length && !result.data) {
33
+ if (!options?.silent) {
34
+ console.warn("[graphql-client] GraphQL errors:", result.errors);
35
+ }
36
+ return null;
37
+ }
38
+ return result.data ?? null;
39
+ }
40
+ catch (error) {
41
+ // Silently fail - this is a fallback mechanism
42
+ if (!options?.silent) {
43
+ console.warn("[graphql-client] Request error:", error);
44
+ }
45
+ return null;
46
+ }
47
+ }
48
+ // Query to get all available drives
49
+ const GET_DRIVES_QUERY = `
50
+ query GetDrives {
51
+ drives
52
+ }
53
+ `;
54
+ // Query to get drive ID by slug
55
+ const GET_DRIVE_ID_BY_SLUG_QUERY = `
56
+ query GetDriveIdBySlug($slug: String!) {
57
+ driveIdBySlug(slug: $slug)
58
+ }
59
+ `;
60
+ // Query to get builder profile documents from a drive
61
+ const GET_BUILDER_PROFILES_QUERY = `
62
+ query GetBuilderProfiles($driveId: String!) {
63
+ BuilderProfile {
64
+ getDocuments(driveId: $driveId) {
65
+ id
66
+ state {
67
+ name
68
+ slug
69
+ icon
70
+ }
71
+ }
72
+ }
73
+ }
74
+ `;
75
+ // Query to get a single builder profile by ID
76
+ const GET_BUILDER_PROFILE_QUERY = `
77
+ query GetBuilderProfile($docId: PHID!, $driveId: PHID) {
78
+ BuilderProfile {
79
+ getDocument(docId: $docId, driveId: $driveId) {
80
+ id
81
+ state {
82
+ name
83
+ slug
84
+ icon
85
+ }
86
+ }
87
+ }
88
+ }
89
+ `;
90
+ /**
91
+ * Fetches all available remote drives
92
+ */
93
+ export async function fetchRemoteDrives() {
94
+ const data = await graphqlRequest(GET_DRIVES_QUERY);
95
+ return data?.drives ?? [];
96
+ }
97
+ /**
98
+ * Fetches drive ID by slug
99
+ */
100
+ export async function fetchDriveIdBySlug(slug) {
101
+ const data = await graphqlRequest(GET_DRIVE_ID_BY_SLUG_QUERY, { slug });
102
+ return data?.driveIdBySlug ?? null;
103
+ }
104
+ /**
105
+ * Fetches all builder profiles from a specific drive
106
+ */
107
+ export async function fetchBuilderProfilesFromDrive(driveId, options) {
108
+ const data = await graphqlRequest(GET_BUILDER_PROFILES_QUERY, { driveId }, options);
109
+ return data?.BuilderProfile?.getDocuments ?? [];
110
+ }
111
+ /**
112
+ * Fetches a single builder profile by document ID
113
+ */
114
+ export async function fetchBuilderProfileById(docId, driveId) {
115
+ const data = await graphqlRequest(GET_BUILDER_PROFILE_QUERY, { docId, driveId });
116
+ return data?.BuilderProfile?.getDocument ?? null;
117
+ }
118
+ /**
119
+ * Fetches all builder profiles from all available remote drives.
120
+ * This aggregates profiles from multiple drives into a single list.
121
+ */
122
+ export async function fetchAllRemoteBuilderProfiles() {
123
+ try {
124
+ const drives = await fetchRemoteDrives();
125
+ if (!drives.length) {
126
+ return [];
127
+ }
128
+ // Fetch profiles from all drives in parallel (silent to avoid console spam)
129
+ const profilePromises = drives.map((driveSlug) => fetchBuilderProfilesFromDrive(driveSlug, { silent: true }).catch(() => []));
130
+ const profileArrays = await Promise.all(profilePromises);
131
+ // Flatten and dedupe by ID
132
+ const profileMap = new Map();
133
+ for (const profiles of profileArrays) {
134
+ for (const profile of profiles) {
135
+ if (!profileMap.has(profile.id)) {
136
+ profileMap.set(profile.id, profile);
137
+ }
138
+ }
139
+ }
140
+ return Array.from(profileMap.values());
141
+ }
142
+ catch {
143
+ return [];
144
+ }
145
+ }
146
+ /**
147
+ * Fetches multiple builder profiles by their IDs.
148
+ * Tries to find them across all available remote drives.
149
+ */
150
+ export async function fetchRemoteBuilderProfilesByIds(phids) {
151
+ if (!phids.length) {
152
+ return new Map();
153
+ }
154
+ try {
155
+ // First, get all profiles from all drives
156
+ const allProfiles = await fetchAllRemoteBuilderProfiles();
157
+ // Filter to only the ones we need
158
+ const result = new Map();
159
+ for (const profile of allProfiles) {
160
+ if (phids.includes(profile.id)) {
161
+ result.set(profile.id, profile);
162
+ }
163
+ }
164
+ // For any missing profiles, try direct fetch
165
+ const missingPhids = phids.filter((phid) => !result.has(phid));
166
+ if (missingPhids.length > 0) {
167
+ const directFetches = missingPhids.map(async (phid) => {
168
+ const profile = await fetchBuilderProfileById(phid);
169
+ if (profile) {
170
+ result.set(phid, profile);
171
+ }
172
+ });
173
+ await Promise.all(directFetches);
174
+ }
175
+ return result;
176
+ }
177
+ catch {
178
+ return new Map();
179
+ }
180
+ }
package/dist/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/builder-team-admin",
3
3
  "description": "Builder Team Admin drive that holds a teams profile and its relevant document models.",
4
- "version": "0.0.3",
4
+ "version": "0.0.4",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
7
7
  "files": [
@@ -62,7 +62,7 @@
62
62
  "service-unstartup": "bash ./node_modules/@powerhousedao/ph-cli/dist/scripts/service-unstartup.sh"
63
63
  },
64
64
  "dependencies": {
65
- "@powerhousedao/builder-profile": "^0.0.6",
65
+ "@powerhousedao/builder-profile": "0.0.7",
66
66
  "@powerhousedao/builder-tools": "^5.1.0",
67
67
  "@powerhousedao/common": "^5.1.0",
68
68
  "@powerhousedao/design-system": "^5.1.0",
package/dist/style.css CHANGED
@@ -140,7 +140,6 @@
140
140
  --animate-spin: spin 1s linear infinite;
141
141
  --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
142
142
  --blur-sm: 8px;
143
- --blur-xl: 24px;
144
143
  --blur-2xl: 40px;
145
144
  --blur-3xl: 64px;
146
145
  --default-transition-duration: 150ms;
@@ -319,9 +318,6 @@
319
318
  .inset-0 {
320
319
  inset: calc(var(--spacing) * 0);
321
320
  }
322
- .-top-16 {
323
- top: calc(var(--spacing) * -16);
324
- }
325
321
  .-top-20 {
326
322
  top: calc(var(--spacing) * -20);
327
323
  }
@@ -331,9 +327,6 @@
331
327
  .top-full {
332
328
  top: 100%;
333
329
  }
334
- .-right-16 {
335
- right: calc(var(--spacing) * -16);
336
- }
337
330
  .-right-20 {
338
331
  right: calc(var(--spacing) * -20);
339
332
  }
@@ -343,18 +336,12 @@
343
336
  .right-4 {
344
337
  right: calc(var(--spacing) * 4);
345
338
  }
346
- .-bottom-12 {
347
- bottom: calc(var(--spacing) * -12);
348
- }
349
339
  .-bottom-16 {
350
340
  bottom: calc(var(--spacing) * -16);
351
341
  }
352
342
  .bottom-4 {
353
343
  bottom: calc(var(--spacing) * 4);
354
344
  }
355
- .-left-12 {
356
- left: calc(var(--spacing) * -12);
357
- }
358
345
  .-left-16 {
359
346
  left: calc(var(--spacing) * -16);
360
347
  }
@@ -505,9 +492,6 @@
505
492
  .h-20 {
506
493
  height: calc(var(--spacing) * 20);
507
494
  }
508
- .h-32 {
509
- height: calc(var(--spacing) * 32);
510
- }
511
495
  .h-48 {
512
496
  height: calc(var(--spacing) * 48);
513
497
  }
@@ -1062,13 +1046,6 @@
1062
1046
  --tw-gradient-from: var(--color-blue-700);
1063
1047
  --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1064
1048
  }
1065
- .from-indigo-200\/30 {
1066
- --tw-gradient-from: color-mix(in srgb, oklch(87% 0.065 274.039) 30%, transparent);
1067
- @supports (color: color-mix(in lab, red, red)) {
1068
- --tw-gradient-from: color-mix(in oklab, var(--color-indigo-200) 30%, transparent);
1069
- }
1070
- --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1071
- }
1072
1049
  .from-indigo-300\/20 {
1073
1050
  --tw-gradient-from: color-mix(in srgb, oklch(78.5% 0.115 274.713) 20%, transparent);
1074
1051
  @supports (color: color-mix(in lab, red, red)) {
@@ -1084,13 +1061,6 @@
1084
1061
  --tw-gradient-from: var(--color-slate-50);
1085
1062
  --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1086
1063
  }
1087
- .from-slate-200\/40 {
1088
- --tw-gradient-from: color-mix(in srgb, hsl(210 9% 48%) 40%, transparent);
1089
- @supports (color: color-mix(in lab, red, red)) {
1090
- --tw-gradient-from: color-mix(in oklab, var(--color-slate-200) 40%, transparent);
1091
- }
1092
- --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1093
- }
1094
1064
  .from-slate-400 {
1095
1065
  --tw-gradient-from: var(--color-slate-400);
1096
1066
  --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
@@ -1118,13 +1088,6 @@
1118
1088
  }
1119
1089
  --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1120
1090
  }
1121
- .to-blue-200\/30 {
1122
- --tw-gradient-to: color-mix(in srgb, hsl(209 97% 85%) 30%, transparent);
1123
- @supports (color: color-mix(in lab, red, red)) {
1124
- --tw-gradient-to: color-mix(in oklab, var(--color-blue-200) 30%, transparent);
1125
- }
1126
- --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1127
- }
1128
1091
  .to-blue-600 {
1129
1092
  --tw-gradient-to: var(--color-blue-600);
1130
1093
  --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
@@ -1136,13 +1099,6 @@
1136
1099
  }
1137
1100
  --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1138
1101
  }
1139
- .to-indigo-200\/30 {
1140
- --tw-gradient-to: color-mix(in srgb, oklch(87% 0.065 274.039) 30%, transparent);
1141
- @supports (color: color-mix(in lab, red, red)) {
1142
- --tw-gradient-to: color-mix(in oklab, var(--color-indigo-200) 30%, transparent);
1143
- }
1144
- --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1145
- }
1146
1102
  .to-indigo-400\/20 {
1147
1103
  --tw-gradient-to: color-mix(in srgb, oklch(67.3% 0.182 276.935) 20%, transparent);
1148
1104
  @supports (color: color-mix(in lab, red, red)) {
@@ -1568,10 +1524,6 @@
1568
1524
  --tw-blur: blur(var(--blur-3xl));
1569
1525
  filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
1570
1526
  }
1571
- .blur-xl {
1572
- --tw-blur: blur(var(--blur-xl));
1573
- filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
1574
- }
1575
1527
  .backdrop-blur-sm {
1576
1528
  --tw-backdrop-blur: blur(var(--blur-sm));
1577
1529
  -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
@@ -1656,6 +1608,48 @@
1656
1608
  }
1657
1609
  }
1658
1610
  }
1611
+ .group-hover\:bg-indigo-100 {
1612
+ &:is(:where(.group):hover *) {
1613
+ @media (hover: hover) {
1614
+ background-color: var(--color-indigo-100);
1615
+ }
1616
+ }
1617
+ }
1618
+ .group-hover\:bg-slate-200 {
1619
+ &:is(:where(.group):hover *) {
1620
+ @media (hover: hover) {
1621
+ background-color: var(--color-slate-200);
1622
+ }
1623
+ }
1624
+ }
1625
+ .group-hover\:text-indigo-500 {
1626
+ &:is(:where(.group):hover *) {
1627
+ @media (hover: hover) {
1628
+ color: var(--color-indigo-500);
1629
+ }
1630
+ }
1631
+ }
1632
+ .group-hover\:text-indigo-600 {
1633
+ &:is(:where(.group):hover *) {
1634
+ @media (hover: hover) {
1635
+ color: var(--color-indigo-600);
1636
+ }
1637
+ }
1638
+ }
1639
+ .group-hover\:text-slate-600 {
1640
+ &:is(:where(.group):hover *) {
1641
+ @media (hover: hover) {
1642
+ color: var(--color-slate-600);
1643
+ }
1644
+ }
1645
+ }
1646
+ .group-hover\:text-slate-700 {
1647
+ &:is(:where(.group):hover *) {
1648
+ @media (hover: hover) {
1649
+ color: var(--color-slate-700);
1650
+ }
1651
+ }
1652
+ }
1659
1653
  .group-hover\:opacity-100 {
1660
1654
  &:is(:where(.group):hover *) {
1661
1655
  @media (hover: hover) {
@@ -1663,6 +1657,13 @@
1663
1657
  }
1664
1658
  }
1665
1659
  }
1660
+ .group-hover\:ring-indigo-200 {
1661
+ &:is(:where(.group):hover *) {
1662
+ @media (hover: hover) {
1663
+ --tw-ring-color: var(--color-indigo-200);
1664
+ }
1665
+ }
1666
+ }
1666
1667
  .last-of-type\:text-gray-800 {
1667
1668
  &:last-of-type {
1668
1669
  color: var(--color-gray-800);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/builder-team-admin",
3
3
  "description": "Builder Team Admin drive that holds a teams profile and its relevant document models.",
4
- "version": "0.0.3",
4
+ "version": "0.0.4",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
7
7
  "files": [
@@ -62,7 +62,7 @@
62
62
  "service-unstartup": "bash ./node_modules/@powerhousedao/ph-cli/dist/scripts/service-unstartup.sh"
63
63
  },
64
64
  "dependencies": {
65
- "@powerhousedao/builder-profile": "^0.0.6",
65
+ "@powerhousedao/builder-profile": "0.0.7",
66
66
  "@powerhousedao/builder-tools": "^5.1.0",
67
67
  "@powerhousedao/common": "^5.1.0",
68
68
  "@powerhousedao/design-system": "^5.1.0",