Skip to content

Commit 8f6cb18

Browse files
committed
improvement(invite-modal): emcn aligned
1 parent fbf7455 commit 8f6cb18

File tree

9 files changed

+619
-572
lines changed

9 files changed

+619
-572
lines changed

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components-new/help-modal/help-modal.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { useCallback, useEffect, useRef, useState } from 'react'
44
import { zodResolver } from '@hookform/resolvers/zod'
55
import imageCompression from 'browser-image-compression'
6-
import { Loader2, X } from 'lucide-react'
6+
import { X } from 'lucide-react'
77
import Image from 'next/image'
88
import { useForm } from 'react-hook-form'
99
import { z } from 'zod'
@@ -419,7 +419,7 @@ export function HelpModal({ open, onOpenChange }: HelpModalProps) {
419419
<ModalHeader>Help &amp; Support</ModalHeader>
420420

421421
<form onSubmit={handleSubmit(onSubmit)} className='flex min-h-0 flex-1 flex-col'>
422-
<ModalBody>
422+
<ModalBody className='!pb-[16px]'>
423423
<div ref={scrollContainerRef} className='min-h-0 flex-1 overflow-y-auto'>
424424
<div className='space-y-[12px]'>
425425
<div>
@@ -554,7 +554,6 @@ export function HelpModal({ open, onOpenChange }: HelpModalProps) {
554554
Cancel
555555
</Button>
556556
<Button type='submit' variant='primary' disabled={isSubmitting || isProcessing}>
557-
{isSubmitting && <Loader2 className='h-4 w-4 animate-spin' />}
558557
{isSubmitting
559558
? 'Submitting...'
560559
: submitStatus === 'error'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react'
2+
import { X } from 'lucide-react'
3+
import { cn } from '@/lib/utils'
4+
5+
export interface EmailTagProps {
6+
email: string
7+
onRemove: () => void
8+
disabled?: boolean
9+
isInvalid?: boolean
10+
isSent?: boolean
11+
}
12+
13+
export const EmailTag = React.memo<EmailTagProps>(
14+
({ email, onRemove, disabled, isInvalid, isSent }) => (
15+
<div
16+
className={cn(
17+
'flex w-auto items-center gap-[4px] rounded-[4px] border px-[8px] py-[4px] text-[12px]',
18+
isInvalid
19+
? 'border-red-200 bg-red-50 text-red-700 dark:border-red-800 dark:bg-red-900/30 dark:text-red-400'
20+
: 'border-[var(--surface-11)] bg-[var(--surface-5)] text-[var(--text-secondary)] dark:bg-[var(--surface-5)] dark:text-[var(--text-secondary)]'
21+
)}
22+
>
23+
<span className='max-w-[200px] truncate'>{email}</span>
24+
{isSent && (
25+
<span className='text-[11px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]'>
26+
sent
27+
</span>
28+
)}
29+
{!disabled && !isSent && (
30+
<button
31+
type='button'
32+
onClick={onRemove}
33+
className={cn(
34+
'flex-shrink-0 transition-colors focus:outline-none',
35+
isInvalid
36+
? 'text-red-400 hover:text-red-600 dark:text-red-400 dark:hover:text-red-300'
37+
: 'text-[var(--text-tertiary)] hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:hover:text-[var(--text-primary)]'
38+
)}
39+
aria-label={`Remove ${email}`}
40+
>
41+
<X className='h-[14px] w-[14px]' />
42+
</button>
43+
)}
44+
</div>
45+
)
46+
)
47+
48+
EmailTag.displayName = 'EmailTag'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export * from './email-tag'
2+
export * from './permission-selector'
3+
export * from './permissions-table'
4+
export * from './permissions-table-skeleton'
5+
export * from './types'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React, { useMemo } from 'react'
2+
import { Button } from '@/components/emcn'
3+
import type { PermissionType } from '@/lib/permissions/utils'
4+
import { cn } from '@/lib/utils'
5+
6+
export interface PermissionSelectorProps {
7+
value: PermissionType
8+
onChange: (value: PermissionType) => void
9+
disabled?: boolean
10+
className?: string
11+
}
12+
13+
export const PermissionSelector = React.memo<PermissionSelectorProps>(
14+
({ value, onChange, disabled = false, className = '' }) => {
15+
const permissionOptions = useMemo(
16+
() => [
17+
{ value: 'read' as PermissionType, label: 'Read' },
18+
{ value: 'write' as PermissionType, label: 'Write' },
19+
{ value: 'admin' as PermissionType, label: 'Admin' },
20+
],
21+
[]
22+
)
23+
24+
return (
25+
<div className={cn('inline-flex gap-[2px]', className)}>
26+
{permissionOptions.map((option, index) => {
27+
const radiusClasses =
28+
index === 0
29+
? 'rounded-r-none'
30+
: index === permissionOptions.length - 1
31+
? 'rounded-l-none'
32+
: 'rounded-none'
33+
34+
return (
35+
<Button
36+
key={option.value}
37+
type='button'
38+
variant={value === option.value ? 'active' : 'default'}
39+
onClick={() => !disabled && onChange(option.value)}
40+
disabled={disabled}
41+
className={cn(
42+
'px-[8px] py-[4px] text-[12px]',
43+
radiusClasses,
44+
disabled && 'cursor-not-allowed'
45+
)}
46+
>
47+
{option.label}
48+
</Button>
49+
)
50+
})}
51+
</div>
52+
)
53+
}
54+
)
55+
56+
PermissionSelector.displayName = 'PermissionSelector'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react'
2+
import { Skeleton } from '@/components/ui/skeleton'
3+
4+
export const PermissionsTableSkeleton = React.memo(() => (
5+
<div className='scrollbar-hide max-h-[300px] overflow-y-auto'>
6+
<div className='flex items-center justify-between gap-[8px] py-[8px]'>
7+
<div className='min-w-0 flex-1'>
8+
<div className='flex items-center gap-[8px]'>
9+
<Skeleton className='h-[14px] w-40 rounded-[4px]' />
10+
</div>
11+
</div>
12+
<div className='flex flex-shrink-0 items-center'>
13+
<div className='inline-flex gap-[2px]'>
14+
<Skeleton className='h-[28px] w-[52px] rounded-[4px]' />
15+
<Skeleton className='h-[28px] w-[52px] rounded-[4px]' />
16+
<Skeleton className='h-[28px] w-[52px] rounded-[4px]' />
17+
</div>
18+
</div>
19+
</div>
20+
</div>
21+
))
22+
23+
PermissionsTableSkeleton.displayName = 'PermissionsTableSkeleton'

0 commit comments

Comments
 (0)