@tuturuuu/ui 0.19.0 → 0.20.1
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.
- package/CHANGELOG.md +46 -0
- package/biome.json +1 -1
- package/package.json +62 -50
- package/src/components/ui/badge.tsx +2 -0
- package/src/components/ui/button.tsx +2 -0
- package/src/components/ui/custom/__tests__/settings-dialog-shell.test.tsx +48 -4
- package/src/components/ui/custom/__tests__/workspace-select-helpers.test.ts +22 -0
- package/src/components/ui/custom/animated-slot-text.tsx +20 -0
- package/src/components/ui/custom/common-footer.tsx +262 -237
- package/src/components/ui/custom/language-dropdown-item.tsx +3 -10
- package/src/components/ui/custom/language-toggle.test.tsx +30 -0
- package/src/components/ui/custom/language-toggle.tsx +11 -10
- package/src/components/ui/custom/locale-preference.ts +32 -0
- package/src/components/ui/custom/settings/appearance-settings.tsx +5 -13
- package/src/components/ui/custom/settings-dialog-shell.tsx +40 -9
- package/src/components/ui/custom/structure.tsx +12 -0
- package/src/components/ui/custom/system-language-dropdown-item.tsx +3 -6
- package/src/components/ui/custom/workspace-access/adapters.test.ts +10 -1
- package/src/components/ui/custom/workspace-access/adapters.ts +36 -4
- package/src/components/ui/custom/workspace-access/member-filter-utils.test.ts +14 -0
- package/src/components/ui/custom/workspace-access/member-filter-utils.ts +8 -0
- package/src/components/ui/custom/workspace-access/types.ts +20 -0
- package/src/components/ui/custom/workspace-access/workspace-access-context.test.tsx +111 -0
- package/src/components/ui/custom/workspace-access/workspace-access-default-role-card.tsx +15 -5
- package/src/components/ui/custom/workspace-access/workspace-access-invite-dialog.tsx +155 -48
- package/src/components/ui/custom/workspace-access/workspace-access-member-profile-dialog.tsx +92 -0
- package/src/components/ui/custom/workspace-access/workspace-access-member-row.tsx +171 -76
- package/src/components/ui/custom/workspace-access/workspace-access-members.tsx +11 -2
- package/src/components/ui/custom/workspace-access/workspace-access-page-header.tsx +11 -11
- package/src/components/ui/custom/workspace-access/workspace-access-page.tsx +180 -22
- package/src/components/ui/custom/workspace-access/workspace-access-people-filters.tsx +29 -15
- package/src/components/ui/custom/workspace-access/workspace-access-permission-checklist.tsx +56 -10
- package/src/components/ui/custom/workspace-access/workspace-access-permission-preview.test.ts +33 -0
- package/src/components/ui/custom/workspace-access/workspace-access-permission-preview.tsx +24 -1
- package/src/components/ui/custom/workspace-access/workspace-access-responsive.test.ts +64 -0
- package/src/components/ui/custom/workspace-access/workspace-access-role-editor-dialog.tsx +28 -16
- package/src/components/ui/custom/workspace-access/workspace-access-roles.tsx +35 -11
- package/src/components/ui/custom/workspace-access/workspace-access-tabs-toolbar.tsx +23 -11
- package/src/components/ui/custom/workspace-select-helpers.ts +5 -3
- package/src/components/ui/custom/workspace-select.tsx +8 -2
- package/src/components/ui/finance/shared/charts/monthly-total-chart-client.tsx +1 -1
- package/src/components/ui/finance/shared/charts/monthly-total-chart.tsx +1 -1
- package/src/components/ui/storefront/cart-summary.tsx +12 -2
- package/src/components/ui/storefront/storefront-surface.test.tsx +21 -0
- package/src/components/ui/storefront/storefront-surface.tsx +6 -0
- package/src/components/ui/text-editor/__tests__/collaboration-binding.test.tsx +161 -0
- package/src/components/ui/text-editor/editor.tsx +267 -235
- package/src/globals.css +166 -0
- package/src/hooks/__tests__/use-workspace-identity-mutation.test.tsx +181 -0
- package/src/hooks/use-workspace-identity-mutation.ts +136 -0
- package/vendor/xlsx/LICENSE +201 -0
- package/vendor/xlsx/types/index.d.ts +1065 -0
- package/vendor/xlsx/xlsx.js +28103 -0
- package/vendor/xlsx/xlsx.mjs +28228 -0
- package/vendor/xlsx-0.20.3.tgz +0 -0
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
Crown,
|
|
5
|
+
Ellipsis,
|
|
6
|
+
Pencil,
|
|
7
|
+
Plus,
|
|
5
8
|
ShieldUser,
|
|
6
9
|
User as UserIcon,
|
|
7
10
|
UserMinus,
|
|
@@ -12,18 +15,23 @@ import { Avatar, AvatarFallback, AvatarImage } from '@tuturuuu/ui/avatar';
|
|
|
12
15
|
import { Badge } from '@tuturuuu/ui/badge';
|
|
13
16
|
import { Button } from '@tuturuuu/ui/button';
|
|
14
17
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
DropdownMenu,
|
|
19
|
+
DropdownMenuContent,
|
|
20
|
+
DropdownMenuItem,
|
|
21
|
+
DropdownMenuLabel,
|
|
22
|
+
DropdownMenuSeparator,
|
|
23
|
+
DropdownMenuSub,
|
|
24
|
+
DropdownMenuSubContent,
|
|
25
|
+
DropdownMenuSubTrigger,
|
|
26
|
+
DropdownMenuTrigger,
|
|
27
|
+
} from '@tuturuuu/ui/dropdown-menu';
|
|
21
28
|
import { getInitials } from '@tuturuuu/utils/name-helper';
|
|
22
29
|
import moment from 'moment';
|
|
23
30
|
import { useLocale, useTranslations } from 'next-intl';
|
|
24
31
|
import {
|
|
25
32
|
getAvailableRolesForMember,
|
|
26
33
|
getMemberDisplayName,
|
|
34
|
+
shouldShowProtectedMemberStatus,
|
|
27
35
|
} from './member-filter-utils';
|
|
28
36
|
import type { WorkspaceAccessLabels, WorkspaceAccessRole } from './types';
|
|
29
37
|
|
|
@@ -35,12 +43,15 @@ type GuestContext = InternalApiEnhancedWorkspaceMember & {
|
|
|
35
43
|
};
|
|
36
44
|
|
|
37
45
|
type Props = {
|
|
46
|
+
canEditProfiles: boolean;
|
|
38
47
|
canManageMembers: boolean;
|
|
39
48
|
canManageRoles: boolean;
|
|
49
|
+
defaultAdminEnabled: boolean;
|
|
40
50
|
isMutating: boolean;
|
|
41
51
|
labels: WorkspaceAccessLabels;
|
|
42
52
|
member: InternalApiEnhancedWorkspaceMember;
|
|
43
53
|
onAssignRole: (payload: { roleId: string; userId: string }) => void;
|
|
54
|
+
onEditMemberProfile: (member: InternalApiEnhancedWorkspaceMember) => void;
|
|
44
55
|
onRemoveMember: (payload: {
|
|
45
56
|
email?: null | string;
|
|
46
57
|
userId?: null | string;
|
|
@@ -50,12 +61,15 @@ type Props = {
|
|
|
50
61
|
};
|
|
51
62
|
|
|
52
63
|
export function WorkspaceAccessMemberRow({
|
|
64
|
+
canEditProfiles,
|
|
53
65
|
canManageMembers,
|
|
54
66
|
canManageRoles,
|
|
67
|
+
defaultAdminEnabled,
|
|
55
68
|
isMutating,
|
|
56
69
|
labels,
|
|
57
70
|
member,
|
|
58
71
|
onAssignRole,
|
|
72
|
+
onEditMemberProfile,
|
|
59
73
|
onRemoveMember,
|
|
60
74
|
onRemoveRole,
|
|
61
75
|
roles,
|
|
@@ -67,6 +81,21 @@ export function WorkspaceAccessMemberRow({
|
|
|
67
81
|
const memberName = getMemberDisplayName(member, t('common.unknown'));
|
|
68
82
|
const guest = member as GuestContext;
|
|
69
83
|
const canRemoveRoles = canManageRoles && memberId && !member.pending;
|
|
84
|
+
const canEditProfile =
|
|
85
|
+
canEditProfiles &&
|
|
86
|
+
canManageMembers &&
|
|
87
|
+
!guest.direct_board_guest &&
|
|
88
|
+
Boolean(memberId || member.email);
|
|
89
|
+
const inheritsAdministrator =
|
|
90
|
+
defaultAdminEnabled &&
|
|
91
|
+
!member.pending &&
|
|
92
|
+
!guest.direct_board_guest &&
|
|
93
|
+
member.workspace_member_type !== 'GUEST';
|
|
94
|
+
const hasActions =
|
|
95
|
+
Boolean(canRemoveRoles) ||
|
|
96
|
+
canEditProfile ||
|
|
97
|
+
(canManageMembers && !member.is_creator) ||
|
|
98
|
+
shouldShowProtectedMemberStatus({ isCreator: member.is_creator });
|
|
70
99
|
|
|
71
100
|
const accent = member.pending
|
|
72
101
|
? 'before:bg-dynamic-orange'
|
|
@@ -78,11 +107,11 @@ export function WorkspaceAccessMemberRow({
|
|
|
78
107
|
|
|
79
108
|
return (
|
|
80
109
|
<article
|
|
81
|
-
className={`group relative overflow-hidden rounded-xl border bg-background pl-
|
|
110
|
+
className={`group relative overflow-hidden rounded-xl border bg-background pl-4 transition-colors before:absolute before:inset-y-0 before:left-0 before:w-1 hover:border-foreground/20 sm:pl-5 ${accent} ${member.pending ? 'border-dashed' : ''}`}
|
|
82
111
|
>
|
|
83
|
-
<div className="p-4 pl-0">
|
|
84
|
-
<div className="flex items-start gap-3">
|
|
85
|
-
<Avatar className="
|
|
112
|
+
<div className="p-3 pl-0 sm:p-4 sm:pl-0">
|
|
113
|
+
<div className="flex items-start gap-2.5 sm:gap-3">
|
|
114
|
+
<Avatar className="size-10 border border-border sm:size-11">
|
|
86
115
|
<AvatarImage src={member.avatar_url ?? undefined} />
|
|
87
116
|
<AvatarFallback className="font-semibold">
|
|
88
117
|
{member.display_name ? (
|
|
@@ -95,7 +124,9 @@ export function WorkspaceAccessMemberRow({
|
|
|
95
124
|
|
|
96
125
|
<div className="min-w-0 flex-1">
|
|
97
126
|
<div className="flex flex-wrap items-center gap-1.5">
|
|
98
|
-
<p className="truncate font-semibold text-base">
|
|
127
|
+
<p className="truncate font-semibold text-sm sm:text-base">
|
|
128
|
+
{memberName}
|
|
129
|
+
</p>
|
|
99
130
|
{member.is_creator ? (
|
|
100
131
|
<Badge className="h-5 gap-1 border-dynamic-yellow/50 bg-dynamic-yellow/10 px-1.5 text-dynamic-yellow text-xs">
|
|
101
132
|
<Crown className="h-3 w-3" />
|
|
@@ -122,14 +153,134 @@ export function WorkspaceAccessMemberRow({
|
|
|
122
153
|
</Badge>
|
|
123
154
|
) : null}
|
|
124
155
|
</div>
|
|
125
|
-
<p className="mt-0.5 truncate text-muted-foreground text-sm">
|
|
156
|
+
<p className="mt-0.5 truncate text-muted-foreground text-xs sm:text-sm">
|
|
126
157
|
{member.email ||
|
|
127
158
|
(member.handle ? `@${member.handle}` : t('common.unknown'))}
|
|
128
159
|
</p>
|
|
129
160
|
</div>
|
|
161
|
+
|
|
162
|
+
{hasActions ? (
|
|
163
|
+
<DropdownMenu>
|
|
164
|
+
<DropdownMenuTrigger asChild>
|
|
165
|
+
<Button
|
|
166
|
+
variant="ghost"
|
|
167
|
+
size="icon"
|
|
168
|
+
className="size-8 shrink-0"
|
|
169
|
+
disabled={isMutating}
|
|
170
|
+
aria-label={t('common.actions')}
|
|
171
|
+
>
|
|
172
|
+
<Ellipsis className="size-4" />
|
|
173
|
+
</Button>
|
|
174
|
+
</DropdownMenuTrigger>
|
|
175
|
+
<DropdownMenuContent align="end" className="w-56">
|
|
176
|
+
{canRemoveRoles ? (
|
|
177
|
+
<>
|
|
178
|
+
<DropdownMenuSub>
|
|
179
|
+
<DropdownMenuSubTrigger>
|
|
180
|
+
<Plus className="size-4" />
|
|
181
|
+
{labels.assignRolePlaceholder}
|
|
182
|
+
</DropdownMenuSubTrigger>
|
|
183
|
+
<DropdownMenuSubContent className="w-52">
|
|
184
|
+
{availableRoles.length === 0 ? (
|
|
185
|
+
<DropdownMenuItem disabled>
|
|
186
|
+
{labels.noAdditionalRoles}
|
|
187
|
+
</DropdownMenuItem>
|
|
188
|
+
) : (
|
|
189
|
+
availableRoles.map((role) => (
|
|
190
|
+
<DropdownMenuItem
|
|
191
|
+
key={role.id}
|
|
192
|
+
onSelect={() =>
|
|
193
|
+
onAssignRole({
|
|
194
|
+
roleId: role.id,
|
|
195
|
+
userId: memberId,
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
>
|
|
199
|
+
<ShieldUser className="size-4" />
|
|
200
|
+
{role.name}
|
|
201
|
+
</DropdownMenuItem>
|
|
202
|
+
))
|
|
203
|
+
)}
|
|
204
|
+
</DropdownMenuSubContent>
|
|
205
|
+
</DropdownMenuSub>
|
|
206
|
+
|
|
207
|
+
{member.roles.length > 0 ? (
|
|
208
|
+
<DropdownMenuSub>
|
|
209
|
+
<DropdownMenuSubTrigger>
|
|
210
|
+
<X className="size-4" />
|
|
211
|
+
{t('common.remove')}
|
|
212
|
+
</DropdownMenuSubTrigger>
|
|
213
|
+
<DropdownMenuSubContent className="w-52">
|
|
214
|
+
{member.roles.map((role) => (
|
|
215
|
+
<DropdownMenuItem
|
|
216
|
+
key={role.id}
|
|
217
|
+
variant="destructive"
|
|
218
|
+
onSelect={() =>
|
|
219
|
+
onRemoveRole({
|
|
220
|
+
roleId: role.id,
|
|
221
|
+
userId: memberId,
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
>
|
|
225
|
+
<X className="size-4" />
|
|
226
|
+
{role.name}
|
|
227
|
+
</DropdownMenuItem>
|
|
228
|
+
))}
|
|
229
|
+
</DropdownMenuSubContent>
|
|
230
|
+
</DropdownMenuSub>
|
|
231
|
+
) : null}
|
|
232
|
+
</>
|
|
233
|
+
) : null}
|
|
234
|
+
|
|
235
|
+
{canEditProfile ? (
|
|
236
|
+
<>
|
|
237
|
+
{canRemoveRoles ? <DropdownMenuSeparator /> : null}
|
|
238
|
+
<DropdownMenuItem
|
|
239
|
+
onSelect={() => onEditMemberProfile(member)}
|
|
240
|
+
>
|
|
241
|
+
<Pencil className="size-4" />
|
|
242
|
+
{t('ws-members.profile_display_name')}
|
|
243
|
+
</DropdownMenuItem>
|
|
244
|
+
</>
|
|
245
|
+
) : null}
|
|
246
|
+
|
|
247
|
+
{member.is_creator ? (
|
|
248
|
+
<>
|
|
249
|
+
{canRemoveRoles || canEditProfile ? (
|
|
250
|
+
<DropdownMenuSeparator />
|
|
251
|
+
) : null}
|
|
252
|
+
<DropdownMenuLabel className="flex items-center gap-2 text-muted-foreground">
|
|
253
|
+
<ShieldUser className="size-4" />
|
|
254
|
+
{labels.protectedMemberLabel}
|
|
255
|
+
</DropdownMenuLabel>
|
|
256
|
+
</>
|
|
257
|
+
) : null}
|
|
258
|
+
|
|
259
|
+
{canManageMembers && !member.is_creator ? (
|
|
260
|
+
<>
|
|
261
|
+
{canRemoveRoles || canEditProfile ? (
|
|
262
|
+
<DropdownMenuSeparator />
|
|
263
|
+
) : null}
|
|
264
|
+
<DropdownMenuItem
|
|
265
|
+
variant="destructive"
|
|
266
|
+
onSelect={() =>
|
|
267
|
+
onRemoveMember({
|
|
268
|
+
email: member.email,
|
|
269
|
+
userId: member.id,
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
>
|
|
273
|
+
<UserMinus className="size-4" />
|
|
274
|
+
{labels.removeMemberAction}
|
|
275
|
+
</DropdownMenuItem>
|
|
276
|
+
</>
|
|
277
|
+
) : null}
|
|
278
|
+
</DropdownMenuContent>
|
|
279
|
+
</DropdownMenu>
|
|
280
|
+
) : null}
|
|
130
281
|
</div>
|
|
131
282
|
|
|
132
|
-
<div className="mt-
|
|
283
|
+
<div className="mt-2.5 flex flex-wrap gap-1.5 sm:mt-3">
|
|
133
284
|
{member.roles.length > 0 ? (
|
|
134
285
|
member.roles.map((role) => (
|
|
135
286
|
<Badge
|
|
@@ -137,20 +288,13 @@ export function WorkspaceAccessMemberRow({
|
|
|
137
288
|
className="h-5 gap-1 border-dynamic-purple/40 bg-dynamic-purple/10 px-1.5 text-dynamic-purple text-xs"
|
|
138
289
|
>
|
|
139
290
|
<span>{role.name}</span>
|
|
140
|
-
{canRemoveRoles ? (
|
|
141
|
-
<button
|
|
142
|
-
type="button"
|
|
143
|
-
className="rounded-full p-0.5 transition-colors hover:bg-dynamic-purple/20"
|
|
144
|
-
onClick={() =>
|
|
145
|
-
onRemoveRole({ roleId: role.id, userId: memberId })
|
|
146
|
-
}
|
|
147
|
-
aria-label={t('common.delete')}
|
|
148
|
-
>
|
|
149
|
-
<X className="h-3 w-3" />
|
|
150
|
-
</button>
|
|
151
|
-
) : null}
|
|
152
291
|
</Badge>
|
|
153
292
|
))
|
|
293
|
+
) : inheritsAdministrator ? (
|
|
294
|
+
<Badge className="h-5 gap-1 border-dynamic-green/40 bg-dynamic-green/10 px-1.5 text-dynamic-green text-xs">
|
|
295
|
+
<ShieldUser className="size-3" />
|
|
296
|
+
{t('ws-roles.admin')}
|
|
297
|
+
</Badge>
|
|
154
298
|
) : (
|
|
155
299
|
<Badge variant="outline" className="h-5 px-1.5 text-xs">
|
|
156
300
|
{labels.noRolesLabel}
|
|
@@ -159,7 +303,7 @@ export function WorkspaceAccessMemberRow({
|
|
|
159
303
|
</div>
|
|
160
304
|
|
|
161
305
|
{guest.direct_board_guest ? (
|
|
162
|
-
<div className="mt-3 rounded-lg border border-dynamic-blue/20 bg-dynamic-blue/5 p-
|
|
306
|
+
<div className="mt-3 rounded-lg border border-dynamic-blue/20 bg-dynamic-blue/5 p-2.5 text-sm sm:p-3">
|
|
163
307
|
<div className="font-medium text-dynamic-blue">
|
|
164
308
|
{t('ws-members.direct_board_guest_scope_title')}
|
|
165
309
|
</div>
|
|
@@ -185,7 +329,7 @@ export function WorkspaceAccessMemberRow({
|
|
|
185
329
|
</div>
|
|
186
330
|
) : null}
|
|
187
331
|
|
|
188
|
-
<div className="mt-3
|
|
332
|
+
<div className="mt-3 border-border border-t pt-3 text-sm">
|
|
189
333
|
{member.created_at ? (
|
|
190
334
|
<div className="text-muted-foreground text-xs">
|
|
191
335
|
<span>
|
|
@@ -202,55 +346,6 @@ export function WorkspaceAccessMemberRow({
|
|
|
202
346
|
) : (
|
|
203
347
|
<span />
|
|
204
348
|
)}
|
|
205
|
-
|
|
206
|
-
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
|
|
207
|
-
{canRemoveRoles ? (
|
|
208
|
-
<Select
|
|
209
|
-
onValueChange={(roleId) =>
|
|
210
|
-
onAssignRole({ roleId, userId: memberId })
|
|
211
|
-
}
|
|
212
|
-
>
|
|
213
|
-
<SelectTrigger className="h-9 min-w-[180px]">
|
|
214
|
-
<SelectValue placeholder={labels.assignRolePlaceholder} />
|
|
215
|
-
</SelectTrigger>
|
|
216
|
-
<SelectContent>
|
|
217
|
-
{availableRoles.length === 0 ? (
|
|
218
|
-
<SelectItem value="__no_roles__" disabled>
|
|
219
|
-
{labels.noAdditionalRoles}
|
|
220
|
-
</SelectItem>
|
|
221
|
-
) : (
|
|
222
|
-
availableRoles.map((role) => (
|
|
223
|
-
<SelectItem key={role.id} value={role.id}>
|
|
224
|
-
{role.name}
|
|
225
|
-
</SelectItem>
|
|
226
|
-
))
|
|
227
|
-
)}
|
|
228
|
-
</SelectContent>
|
|
229
|
-
</Select>
|
|
230
|
-
) : null}
|
|
231
|
-
|
|
232
|
-
{canManageMembers && !member.is_creator ? (
|
|
233
|
-
<Button
|
|
234
|
-
variant="outline"
|
|
235
|
-
size="sm"
|
|
236
|
-
disabled={isMutating}
|
|
237
|
-
onClick={() =>
|
|
238
|
-
onRemoveMember({
|
|
239
|
-
email: member.email,
|
|
240
|
-
userId: member.pending ? null : member.id,
|
|
241
|
-
})
|
|
242
|
-
}
|
|
243
|
-
>
|
|
244
|
-
<UserMinus className="mr-2 h-4 w-4" />
|
|
245
|
-
{labels.removeMemberAction}
|
|
246
|
-
</Button>
|
|
247
|
-
) : (
|
|
248
|
-
<div className="inline-flex items-center gap-2 rounded-md border border-border px-3 py-1.5 text-muted-foreground text-xs">
|
|
249
|
-
<ShieldUser className="h-3.5 w-3.5" />
|
|
250
|
-
{labels.protectedMemberLabel}
|
|
251
|
-
</div>
|
|
252
|
-
)}
|
|
253
|
-
</div>
|
|
254
349
|
</div>
|
|
255
350
|
</div>
|
|
256
351
|
</article>
|
|
@@ -8,13 +8,16 @@ import type { WorkspaceAccessLabels, WorkspaceAccessRole } from './types';
|
|
|
8
8
|
import { WorkspaceAccessMemberRow } from './workspace-access-member-row';
|
|
9
9
|
|
|
10
10
|
type Props = {
|
|
11
|
+
canEditProfiles: boolean;
|
|
11
12
|
canManageMembers: boolean;
|
|
12
13
|
canManageRoles: boolean;
|
|
14
|
+
defaultAdminEnabled: boolean;
|
|
13
15
|
isLoading: boolean;
|
|
14
16
|
isMutating: boolean;
|
|
15
17
|
labels: WorkspaceAccessLabels;
|
|
16
18
|
members: InternalApiEnhancedWorkspaceMember[];
|
|
17
19
|
onAssignRole: (payload: { roleId: string; userId: string }) => void;
|
|
20
|
+
onEditMemberProfile: (member: InternalApiEnhancedWorkspaceMember) => void;
|
|
18
21
|
onRemoveMember: (payload: {
|
|
19
22
|
email?: null | string;
|
|
20
23
|
userId?: null | string;
|
|
@@ -26,13 +29,16 @@ type Props = {
|
|
|
26
29
|
};
|
|
27
30
|
|
|
28
31
|
export function WorkspaceAccessMembers({
|
|
32
|
+
canEditProfiles,
|
|
29
33
|
canManageMembers,
|
|
30
34
|
canManageRoles,
|
|
35
|
+
defaultAdminEnabled,
|
|
31
36
|
isLoading,
|
|
32
37
|
isMutating,
|
|
33
38
|
labels,
|
|
34
39
|
members,
|
|
35
40
|
onAssignRole,
|
|
41
|
+
onEditMemberProfile,
|
|
36
42
|
onRemoveMember,
|
|
37
43
|
onRemoveRole,
|
|
38
44
|
roles,
|
|
@@ -43,7 +49,7 @@ export function WorkspaceAccessMembers({
|
|
|
43
49
|
|
|
44
50
|
if (isLoading) {
|
|
45
51
|
return (
|
|
46
|
-
<div className="grid gap-
|
|
52
|
+
<div className="grid gap-3 lg:grid-cols-2">
|
|
47
53
|
<Skeleton className="h-48 rounded-xl" />
|
|
48
54
|
<Skeleton className="h-48 rounded-xl" />
|
|
49
55
|
<Skeleton className="h-48 rounded-xl" />
|
|
@@ -70,16 +76,19 @@ export function WorkspaceAccessMembers({
|
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
return (
|
|
73
|
-
<div className="grid gap-
|
|
79
|
+
<div className="grid gap-3 lg:grid-cols-2">
|
|
74
80
|
{members.map((member) => (
|
|
75
81
|
<WorkspaceAccessMemberRow
|
|
76
82
|
key={`${member.id ?? member.email ?? member.handle}`}
|
|
83
|
+
canEditProfiles={canEditProfiles}
|
|
77
84
|
canManageMembers={canManageMembers}
|
|
78
85
|
canManageRoles={canManageRoles}
|
|
86
|
+
defaultAdminEnabled={defaultAdminEnabled}
|
|
79
87
|
isMutating={isMutating}
|
|
80
88
|
labels={labels}
|
|
81
89
|
member={member}
|
|
82
90
|
onAssignRole={onAssignRole}
|
|
91
|
+
onEditMemberProfile={onEditMemberProfile}
|
|
83
92
|
onRemoveMember={onRemoveMember}
|
|
84
93
|
onRemoveRole={onRemoveRole}
|
|
85
94
|
roles={roles}
|
|
@@ -51,25 +51,25 @@ export function WorkspaceAccessPageHeader({
|
|
|
51
51
|
];
|
|
52
52
|
|
|
53
53
|
return (
|
|
54
|
-
<section className="rounded-xl border border-border bg-background">
|
|
55
|
-
<div className="flex flex-col gap-
|
|
56
|
-
<div className="flex min-w-0 gap-4">
|
|
57
|
-
<div className="flex
|
|
54
|
+
<section className="overflow-hidden rounded-xl border border-border bg-background">
|
|
55
|
+
<div className="flex flex-col gap-4 p-4 sm:p-6 lg:flex-row lg:items-start lg:justify-between">
|
|
56
|
+
<div className="flex min-w-0 gap-3 sm:gap-4">
|
|
57
|
+
<div className="flex size-10 shrink-0 items-center justify-center rounded-xl border border-dynamic-blue/30 bg-dynamic-blue/10 text-dynamic-blue sm:size-11">
|
|
58
58
|
<Users className="h-5 w-5" />
|
|
59
59
|
</div>
|
|
60
60
|
<div className="min-w-0">
|
|
61
61
|
<div className="flex items-center gap-2">
|
|
62
|
-
<h1 className="truncate font-bold text-
|
|
62
|
+
<h1 className="truncate font-bold text-xl tracking-tight sm:text-2xl">
|
|
63
63
|
{mode === 'cms'
|
|
64
64
|
? t('external-projects.settings.members_title')
|
|
65
65
|
: t('workspace-settings-layout.members')}
|
|
66
66
|
</h1>
|
|
67
|
-
<span className="
|
|
67
|
+
<span className="hidden items-center gap-1 rounded-full border border-dynamic-purple/30 bg-dynamic-purple/10 px-2 py-0.5 font-medium text-dynamic-purple text-xs sm:inline-flex">
|
|
68
68
|
<ShieldCheck className="h-3 w-3" />
|
|
69
69
|
{t('ws-roles.plural')}
|
|
70
70
|
</span>
|
|
71
71
|
</div>
|
|
72
|
-
<p className="mt-1
|
|
72
|
+
<p className="mt-1 max-w-2xl text-muted-foreground text-sm leading-5 sm:mt-1.5 sm:leading-6">
|
|
73
73
|
{mode === 'cms'
|
|
74
74
|
? t('external-projects.settings.members_description')
|
|
75
75
|
: t('ws-members.description')}
|
|
@@ -85,21 +85,21 @@ export function WorkspaceAccessPageHeader({
|
|
|
85
85
|
</div>
|
|
86
86
|
</div>
|
|
87
87
|
|
|
88
|
-
<div className="grid shrink-0 grid-cols-3 divide-x divide-border overflow-hidden rounded-lg border border-border bg-foreground/[0.02]">
|
|
88
|
+
<div className="grid w-full shrink-0 grid-cols-3 divide-x divide-border overflow-hidden rounded-lg border border-border bg-foreground/[0.02] lg:w-auto">
|
|
89
89
|
{stats.map((stat) => (
|
|
90
90
|
<div
|
|
91
91
|
key={stat.label}
|
|
92
|
-
className="flex flex-col gap-
|
|
92
|
+
className="flex min-w-0 flex-col gap-0.5 px-2 py-2.5 text-center sm:gap-1 sm:px-4 sm:py-3"
|
|
93
93
|
>
|
|
94
94
|
<span
|
|
95
95
|
className={`inline-flex items-center justify-center gap-1.5 ${stat.accent}`}
|
|
96
96
|
>
|
|
97
97
|
{stat.icon}
|
|
98
|
-
<span className="font-bold text-foreground text-
|
|
98
|
+
<span className="font-bold text-foreground text-lg tabular-nums sm:text-xl">
|
|
99
99
|
{stat.value}
|
|
100
100
|
</span>
|
|
101
101
|
</span>
|
|
102
|
-
<span className="text-muted-foreground text-xs">
|
|
102
|
+
<span className="truncate text-[11px] text-muted-foreground sm:text-xs">
|
|
103
103
|
{stat.label}
|
|
104
104
|
</span>
|
|
105
105
|
</div>
|