@invopop/popui 0.1.14 → 0.1.16
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/dist/BaseButton.svelte +25 -103
- package/dist/BaseCard.svelte +35 -30
- package/dist/BaseCounter.svelte +11 -8
- package/dist/BaseDropdown.svelte +3 -3
- package/dist/BaseTable.svelte +8 -12
- package/dist/BaseTableActions.svelte +4 -6
- package/dist/BaseTableCellContent.svelte +4 -6
- package/dist/BaseTableCheckbox.svelte +8 -10
- package/dist/BaseTableHeaderContent.svelte +4 -4
- package/dist/BaseTableRow.svelte +12 -10
- package/dist/Breadcrumb.svelte +40 -0
- package/dist/Breadcrumb.svelte.d.ts +4 -0
- package/dist/Breadcrumbs.svelte +5 -30
- package/dist/ButtonFile.svelte +35 -30
- package/dist/ButtonUuidCopy.svelte +3 -2
- package/dist/CardCheckbox.svelte +25 -21
- package/dist/CardRelation.svelte +12 -16
- package/dist/CompanySelector.svelte +35 -7
- package/dist/DataListItem.svelte +14 -10
- package/dist/DatePicker.svelte +14 -12
- package/dist/DrawerContext.svelte +111 -8
- package/dist/DrawerContextItem.svelte +18 -30
- package/dist/DrawerContextSeparator.svelte +1 -1
- package/dist/DrawerContextWorkspace.svelte +7 -7
- package/dist/DropdownSelect.svelte +38 -16
- package/dist/EmptyState.svelte +42 -0
- package/dist/EmptyState.svelte.d.ts +4 -0
- package/dist/EmptyStateIllustration.svelte.d.ts +0 -1
- package/dist/FeedEvents.svelte +9 -5
- package/dist/FeedIconEvent.svelte +1 -1
- package/dist/FeedIconStatus.svelte +1 -1
- package/dist/FeedItem.svelte +8 -8
- package/dist/FeedItemDetail.svelte +15 -6
- package/dist/GlobalSearch.svelte +13 -12
- package/dist/InputCheckbox.svelte +2 -5
- package/dist/InputError.svelte +4 -9
- package/dist/InputLabel.svelte +3 -1
- package/dist/InputRadio.svelte +26 -11
- package/dist/InputSearch.svelte +8 -8
- package/dist/InputSelect.svelte +32 -31
- package/dist/InputText.svelte +32 -24
- package/dist/InputTextarea.svelte +25 -19
- package/dist/InputToggle.svelte +24 -18
- package/dist/MenuItem.svelte +9 -8
- package/dist/MenuItemCollapsible.svelte +4 -4
- package/dist/Notification.svelte +59 -24
- package/dist/ProfileAvatar.svelte +43 -14
- package/dist/SeparatorHorizontal.svelte +2 -2
- package/dist/ShortcutWrapper.svelte +14 -5
- package/dist/StatusLabel.svelte +4 -5
- package/dist/StepIconList.svelte +11 -9
- package/dist/TagBeta.svelte +26 -14
- package/dist/TagStatus.svelte +37 -49
- package/dist/TitleMain.svelte +1 -1
- package/dist/TitleSection.svelte +1 -1
- package/dist/UuidCopy.svelte +4 -4
- package/dist/alert-dialog/alert-dialog-action.svelte +5 -3
- package/dist/alert-dialog/alert-dialog-cancel.svelte +4 -2
- package/dist/alert-dialog/alert-dialog-content.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-description.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-footer.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-header.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-title.svelte +1 -1
- package/dist/button/button.svelte +198 -24
- package/dist/button/button.svelte.d.ts +48 -26
- package/dist/index.d.ts +5 -10
- package/dist/index.js +3 -13
- package/dist/range-calendar/range-calendar-cell.svelte +1 -1
- package/dist/range-calendar/range-calendar-day.svelte +10 -8
- package/dist/range-calendar/range-calendar-head-cell.svelte +1 -1
- package/dist/range-calendar/range-calendar-next-button.svelte +3 -3
- package/dist/range-calendar/range-calendar-prev-button.svelte +3 -3
- package/dist/range-calendar/range-calendar.svelte +1 -1
- package/dist/sonner/sonner.svelte +7 -9
- package/dist/svg/CheckBadge.svelte +18 -0
- package/dist/svg/CheckBadge.svelte.d.ts +26 -0
- package/dist/svg/IconEmpty.svelte +78 -106
- package/dist/table/table-body.svelte +1 -1
- package/dist/table/table-cell.svelte +1 -1
- package/dist/table/table-footer.svelte +1 -1
- package/dist/table/table-head.svelte +1 -1
- package/dist/table/table-header.svelte +1 -1
- package/dist/table/table-row.svelte +1 -1
- package/dist/tabs/tabs-list.svelte +8 -2
- package/dist/tabs/tabs-list.svelte.d.ts +4 -1
- package/dist/tabs/tabs-trigger.svelte +5 -3
- package/dist/tabs/tabs-trigger.svelte.d.ts +4 -1
- package/dist/tailwind.theme.css +981 -0
- package/dist/tooltip/tooltip-content.svelte +2 -2
- package/dist/types.d.ts +36 -42
- package/package.json +2 -2
- package/dist/CounterWorkflow.svelte +0 -19
- package/dist/CounterWorkflow.svelte.d.ts +0 -4
- package/dist/EmptyStateIcon.svelte +0 -52
- package/dist/EmptyStateIcon.svelte.d.ts +0 -4
- package/dist/FormLayoutModal.svelte +0 -14
- package/dist/FormLayoutModal.svelte.d.ts +0 -4
- package/dist/ProfileSelector.svelte +0 -41
- package/dist/ProfileSelector.svelte.d.ts +0 -4
- package/dist/SectionLayout.svelte +0 -13
- package/dist/SectionLayout.svelte.d.ts +0 -4
- package/dist/tw.theme.d.ts +0 -171
- package/dist/tw.theme.js +0 -188
package/dist/ButtonFile.svelte
CHANGED
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import BaseButton from './BaseButton.svelte'
|
|
2
|
+
import { Download } from '@invopop/ui-icons'
|
|
3
|
+
import Button from './button/button.svelte'
|
|
5
4
|
import type { ButtonFileProps } from './types.js'
|
|
6
|
-
import
|
|
5
|
+
import { cn } from './utils.js'
|
|
7
6
|
|
|
8
7
|
let {
|
|
9
|
-
icon = Invoice,
|
|
10
8
|
name = '',
|
|
11
9
|
disabled = false,
|
|
12
10
|
date = '',
|
|
13
|
-
|
|
11
|
+
fileType = 'pdf',
|
|
14
12
|
onPreview,
|
|
15
13
|
onDownload,
|
|
14
|
+
class: className,
|
|
16
15
|
...rest
|
|
17
16
|
}: ButtonFileProps = $props()
|
|
18
17
|
|
|
19
|
-
let
|
|
20
|
-
|
|
21
|
-
'
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'border-neutral-100 bg-neutral-50 text-neutral-500': iconColor === 'grey'
|
|
29
|
-
})
|
|
18
|
+
let fileAvatarStyles = $derived(
|
|
19
|
+
cn(
|
|
20
|
+
'size-8 rounded-md border border-border flex items-center justify-center text-xs font-black font-mono leading-4 uppercase',
|
|
21
|
+
{
|
|
22
|
+
'text-foreground-document-pdf': fileType === 'pdf',
|
|
23
|
+
'text-foreground-document-xml': fileType === 'xml',
|
|
24
|
+
'text-foreground-document-png': fileType === 'png'
|
|
25
|
+
}
|
|
26
|
+
)
|
|
30
27
|
)
|
|
31
28
|
|
|
32
29
|
function handleClick(event: MouseEvent) {
|
|
@@ -36,27 +33,35 @@
|
|
|
36
33
|
</script>
|
|
37
34
|
|
|
38
35
|
<button
|
|
39
|
-
class
|
|
40
|
-
|
|
36
|
+
class={cn(
|
|
37
|
+
'flex items-center gap-3 px-2 py-1.5 rounded-[10px] w-full hover:bg-background-default-secondary cursor-pointer',
|
|
38
|
+
disabled && 'opacity-30 pointer-events-none',
|
|
39
|
+
className
|
|
40
|
+
)}
|
|
41
41
|
{disabled}
|
|
42
42
|
{...rest}
|
|
43
43
|
onclick={handleClick}
|
|
44
44
|
>
|
|
45
|
-
<
|
|
46
|
-
<div class=
|
|
47
|
-
|
|
45
|
+
<div class="flex items-center gap-[10px] flex-1 min-w-0">
|
|
46
|
+
<div class={fileAvatarStyles}>
|
|
47
|
+
{fileType}
|
|
48
48
|
</div>
|
|
49
|
-
<div class="flex flex-col
|
|
50
|
-
<
|
|
49
|
+
<div class="flex flex-col text-start min-w-0 flex-1">
|
|
50
|
+
<div class="text-sm font-medium text-foreground truncate w-full">
|
|
51
51
|
{name}
|
|
52
|
-
</
|
|
53
|
-
<
|
|
52
|
+
</div>
|
|
53
|
+
<div class="text-xs text-foreground-default-secondary truncate w-full">
|
|
54
|
+
{date}
|
|
55
|
+
</div>
|
|
54
56
|
</div>
|
|
55
|
-
</
|
|
56
|
-
<
|
|
57
|
-
|
|
57
|
+
</div>
|
|
58
|
+
<Button
|
|
59
|
+
variant="secondary"
|
|
60
|
+
size="md"
|
|
58
61
|
icon={Download}
|
|
59
|
-
|
|
62
|
+
{disabled}
|
|
63
|
+
onclick={(e) => {
|
|
64
|
+
e.stopPropagation()
|
|
60
65
|
onDownload?.()
|
|
61
66
|
}}
|
|
62
67
|
/>
|
|
@@ -28,13 +28,14 @@
|
|
|
28
28
|
|
|
29
29
|
<BaseButton
|
|
30
30
|
{disabled}
|
|
31
|
-
|
|
31
|
+
size="sm"
|
|
32
32
|
icon={Duplicate}
|
|
33
33
|
iconPosition="right"
|
|
34
|
+
variant="ghost"
|
|
34
35
|
onclick={async () => {
|
|
35
36
|
await navigator.clipboard.writeText(uuid)
|
|
36
37
|
oncopied?.(uuid)
|
|
37
38
|
}}
|
|
38
39
|
>
|
|
39
|
-
<span class="font-mono
|
|
40
|
+
<span class="font-mono">{formattedUuid}</span>
|
|
40
41
|
</BaseButton>
|
package/dist/CardCheckbox.svelte
CHANGED
|
@@ -11,47 +11,51 @@
|
|
|
11
11
|
description = '',
|
|
12
12
|
accentText = '',
|
|
13
13
|
checked = false,
|
|
14
|
+
disabled = false,
|
|
14
15
|
icon = undefined,
|
|
15
16
|
hideRadio = false,
|
|
16
17
|
footer,
|
|
17
18
|
onchange
|
|
18
19
|
}: CardCheckboxProps = $props()
|
|
19
20
|
|
|
20
|
-
let
|
|
21
|
-
clsx(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
let containerStyles = $derived(
|
|
22
|
+
clsx('border gap-3 py-2 pr-2 pl-3 flex items-start rounded-xl', {
|
|
23
|
+
'border-foreground-selected': checked,
|
|
24
|
+
'border-border': !checked,
|
|
25
|
+
'bg-background-default-secondary': disabled
|
|
26
|
+
})
|
|
25
27
|
)
|
|
26
28
|
</script>
|
|
27
29
|
|
|
28
|
-
<label for={id} class="
|
|
29
|
-
<div class=
|
|
30
|
-
<div class="flex
|
|
30
|
+
<label for={id} class="cursor-pointer">
|
|
31
|
+
<div class={containerStyles}>
|
|
32
|
+
<div class="flex grow items-start gap-1 min-w-0">
|
|
31
33
|
{#if icon}
|
|
32
|
-
<Icon src={icon} class="
|
|
34
|
+
<Icon src={icon} class="size-4 text-icon shrink-0 mt-0.5" />
|
|
33
35
|
{/if}
|
|
34
|
-
<div class="flex flex-col
|
|
35
|
-
<span class="text-base
|
|
36
|
+
<div class="flex flex-col gap-1 min-w-0">
|
|
37
|
+
<span class="text-base font-medium text-foreground">
|
|
38
|
+
{title}
|
|
39
|
+
</span>
|
|
36
40
|
{#if description}
|
|
37
|
-
<span class="
|
|
41
|
+
<span class="text-sm text-foreground-default-secondary">
|
|
38
42
|
{#if accentText}
|
|
39
|
-
<
|
|
43
|
+
<span class="font-medium text-foreground-accent">{accentText}</span>
|
|
44
|
+
{' · '}
|
|
40
45
|
{/if}
|
|
41
|
-
|
|
42
|
-
{description}
|
|
43
|
-
</p>
|
|
46
|
+
{description}
|
|
44
47
|
</span>
|
|
45
48
|
{/if}
|
|
46
49
|
</div>
|
|
47
50
|
</div>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
{#if !hideRadio}
|
|
52
|
+
<div class="flex items-center p-px">
|
|
53
|
+
<InputRadio {id} {name} {checked} {disabled} {onchange} />
|
|
54
|
+
</div>
|
|
55
|
+
{/if}
|
|
52
56
|
</div>
|
|
53
57
|
{#if footer}
|
|
54
|
-
<div class="bg-
|
|
58
|
+
<div class="border-t border-border bg-background-default-secondary rounded-b-xl px-3 pb-3 pt-2">
|
|
55
59
|
{@render footer?.()}
|
|
56
60
|
</div>
|
|
57
61
|
{/if}
|
package/dist/CardRelation.svelte
CHANGED
|
@@ -2,31 +2,27 @@
|
|
|
2
2
|
import { Icon } from '@steeze-ui/svelte-icon'
|
|
3
3
|
import type { CardRelationProps } from './types.js'
|
|
4
4
|
import { ChevronRight } from '@invopop/ui-icons'
|
|
5
|
-
import SeparatorHorizontal from './SeparatorHorizontal.svelte'
|
|
6
5
|
|
|
7
6
|
let { title = '', icon = undefined, items = [], onclick }: CardRelationProps = $props()
|
|
8
7
|
</script>
|
|
9
8
|
|
|
10
|
-
<div class="border border-
|
|
11
|
-
<button
|
|
12
|
-
class="
|
|
13
|
-
{onclick}
|
|
14
|
-
>
|
|
15
|
-
<div class="flex items-center space-x-1.5">
|
|
9
|
+
<div class="border border-border-default-secondary rounded-2xl overflow-hidden">
|
|
10
|
+
<button class="flex items-center gap-3 px-3 py-2 w-full cursor-pointer" {onclick}>
|
|
11
|
+
<div class="flex grow items-center gap-1.5 min-w-0">
|
|
16
12
|
{#if icon}
|
|
17
|
-
<Icon src={icon} class="
|
|
13
|
+
<Icon src={icon} class="size-4 text-icon shrink-0" />
|
|
18
14
|
{/if}
|
|
19
|
-
<span class="text-base font-medium text-
|
|
15
|
+
<span class="text-base font-medium text-foreground whitespace-nowrap">
|
|
16
|
+
{title}
|
|
17
|
+
</span>
|
|
20
18
|
</div>
|
|
21
|
-
|
|
22
|
-
<Icon src={ChevronRight} class="h-4 w-4 text-neutral-500" />
|
|
19
|
+
<Icon src={ChevronRight} class="size-3 text-icon shrink-0" />
|
|
23
20
|
</button>
|
|
24
|
-
<
|
|
25
|
-
<div class="py-1.5 text-sm">
|
|
21
|
+
<div class="flex flex-col gap-2 px-3 pb-3 pt-2">
|
|
26
22
|
{#each items as item}
|
|
27
|
-
<div class="
|
|
28
|
-
<div class="min-w-[88px] text-
|
|
29
|
-
<div class="text-
|
|
23
|
+
<div class="flex items-center gap-3 text-sm">
|
|
24
|
+
<div class="min-w-[88px] text-foreground-default-secondary shrink-0">{item.label}</div>
|
|
25
|
+
<div class="grow text-foreground min-w-0">{item.value}</div>
|
|
30
26
|
</div>
|
|
31
27
|
{/each}
|
|
32
28
|
</div>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import ProfileAvatar from './ProfileAvatar.svelte'
|
|
3
|
-
import type { AnyProp, CompanySelectorProps, DrawerOption } from './types.js'
|
|
3
|
+
import type { AnyProp, CompanySelectorProps, DrawerOption, DrawerGroup } from './types.js'
|
|
4
4
|
import BaseDropdown from './BaseDropdown.svelte'
|
|
5
|
-
import
|
|
6
|
-
import { DoubleArrow } from '@invopop/ui-icons'
|
|
5
|
+
import DrawerContext from './DrawerContext.svelte'
|
|
6
|
+
import { DoubleArrow, Workspace, AddCircle, ExternalLink } from '@invopop/ui-icons'
|
|
7
7
|
import MenuItemCollapsible from './MenuItemCollapsible.svelte'
|
|
8
8
|
|
|
9
9
|
let companyDropdown: BaseDropdown | undefined = $state()
|
|
@@ -21,6 +21,24 @@
|
|
|
21
21
|
let country = $derived(selectedCompany?.country || '')
|
|
22
22
|
let picture = $derived(selectedCompany?.logo_url || '')
|
|
23
23
|
let isSandbox = $derived(selectedCompany?.sandbox)
|
|
24
|
+
|
|
25
|
+
let groups: DrawerGroup[] = [
|
|
26
|
+
{
|
|
27
|
+
label: 'Live',
|
|
28
|
+
slug: 'live',
|
|
29
|
+
emptyIcon: Workspace,
|
|
30
|
+
emptyTitle: 'No workspaces here',
|
|
31
|
+
emptyDescription: 'Create a workspace to start'
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
label: 'Sandbox',
|
|
35
|
+
slug: 'sandbox',
|
|
36
|
+
emptyIcon: Workspace,
|
|
37
|
+
emptyTitle: 'No workspaces here',
|
|
38
|
+
emptyDescription: 'Create a workspace to start'
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
|
|
24
42
|
let items = $derived([
|
|
25
43
|
...companies.map((c) => ({
|
|
26
44
|
value: c.id,
|
|
@@ -28,8 +46,18 @@
|
|
|
28
46
|
selected: c.slug === selectedCompany?.slug && !!c.sandbox === !!selectedCompany?.sandbox,
|
|
29
47
|
country: c.country,
|
|
30
48
|
picture: c.logo_url,
|
|
31
|
-
sandbox: c.sandbox
|
|
32
|
-
|
|
49
|
+
sandbox: c.sandbox,
|
|
50
|
+
groupBy: c.sandbox ? 'sandbox' : 'live'
|
|
51
|
+
})),
|
|
52
|
+
{
|
|
53
|
+
separator: true
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
value: 'add',
|
|
57
|
+
label: 'Create workspace',
|
|
58
|
+
icon: AddCircle,
|
|
59
|
+
rightIcon: ExternalLink
|
|
60
|
+
}
|
|
33
61
|
] as DrawerOption[])
|
|
34
62
|
|
|
35
63
|
function selectCompany(value: AnyProp) {
|
|
@@ -60,8 +88,8 @@
|
|
|
60
88
|
active={isOpen}
|
|
61
89
|
bold
|
|
62
90
|
>
|
|
63
|
-
<ProfileAvatar {name} {picture} {country} dark
|
|
91
|
+
<ProfileAvatar {name} {picture} {country} dark variant="lg" />
|
|
64
92
|
</MenuItemCollapsible>
|
|
65
93
|
{/snippet}
|
|
66
|
-
<
|
|
94
|
+
<DrawerContext {items} {groups} onclick={selectCompany} widthClass="w-[300px]" />
|
|
67
95
|
</BaseDropdown>
|
package/dist/DataListItem.svelte
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
children
|
|
12
12
|
}: DataListItemProps = $props()
|
|
13
13
|
|
|
14
|
-
let
|
|
15
|
-
clsx({
|
|
14
|
+
let valueStyles = $derived(
|
|
15
|
+
clsx('text-foreground font-medium text-base', {
|
|
16
16
|
'font-mono': monospaced,
|
|
17
17
|
'slashed-zero tabular-nums lining-nums': monospacedNums,
|
|
18
18
|
'w-full': fullWidth
|
|
@@ -20,13 +20,17 @@
|
|
|
20
20
|
)
|
|
21
21
|
</script>
|
|
22
22
|
|
|
23
|
-
<div class="flex
|
|
24
|
-
<div class="text-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
{
|
|
29
|
-
{
|
|
30
|
-
|
|
23
|
+
<div class="flex gap-6 items-center px-3 py-1.5 rounded-lg hover:bg-background-default-secondary">
|
|
24
|
+
<div class="text-foreground-default-secondary text-base min-w-[125px]">
|
|
25
|
+
{label}
|
|
26
|
+
</div>
|
|
27
|
+
<div class="flex gap-1 items-center">
|
|
28
|
+
<div class={valueStyles}>
|
|
29
|
+
{#if children}
|
|
30
|
+
{@render children()}
|
|
31
|
+
{:else}
|
|
32
|
+
{value}
|
|
33
|
+
{/if}
|
|
34
|
+
</div>
|
|
31
35
|
</div>
|
|
32
36
|
</div>
|
package/dist/DatePicker.svelte
CHANGED
|
@@ -120,11 +120,11 @@
|
|
|
120
120
|
start: undefined,
|
|
121
121
|
end: undefined
|
|
122
122
|
})
|
|
123
|
-
let isOpen = $state(
|
|
123
|
+
let isOpen = $state(true)
|
|
124
124
|
let styles = $derived(
|
|
125
125
|
clsx({
|
|
126
|
-
'border-
|
|
127
|
-
'border-
|
|
126
|
+
'border-border-selected-bold shadow-active': isOpen,
|
|
127
|
+
'border-border hover:border-border-default-secondary-hover': !isOpen
|
|
128
128
|
})
|
|
129
129
|
)
|
|
130
130
|
let selectedLabel = $state(label)
|
|
@@ -188,11 +188,11 @@
|
|
|
188
188
|
onclick={() => {
|
|
189
189
|
isOpen = !isOpen
|
|
190
190
|
}}
|
|
191
|
-
class="{styles} datepicker-trigger w-full py-1.25 pl-7 pr-8 border rounded-
|
|
191
|
+
class="{styles} datepicker-trigger w-full py-1.25 pl-7 pr-8 border rounded-lg text-foreground placeholder-foreground text-base cursor-pointer"
|
|
192
192
|
>
|
|
193
193
|
{selectedLabel}
|
|
194
194
|
</button>
|
|
195
|
-
<Icon src={Calendar} class="h-4 w-4 absolute top-2 left-2 text-
|
|
195
|
+
<Icon src={Calendar} class="h-4 w-4 absolute top-2 left-2 text-foreground-default-secondary" />
|
|
196
196
|
</div>
|
|
197
197
|
|
|
198
198
|
<div class="relative">
|
|
@@ -209,21 +209,21 @@
|
|
|
209
209
|
<div
|
|
210
210
|
class:left-0={position === 'left'}
|
|
211
211
|
class:right-0={position === 'right'}
|
|
212
|
-
class="bg-white inline-flex flex-col shadow rounded-
|
|
212
|
+
class="bg-white inline-flex flex-col shadow-lg rounded-xl absolute right-0 top-2 z-40 border border-border"
|
|
213
213
|
use:clickOutside
|
|
214
214
|
onclick_outside={() => {
|
|
215
215
|
if (!isOpen) return
|
|
216
216
|
cancel()
|
|
217
217
|
}}
|
|
218
218
|
>
|
|
219
|
-
<div class="flex border-b border-
|
|
220
|
-
<div class="flex flex-col space-y-2 items-start p-3 border-r border-
|
|
219
|
+
<div class="flex border-b border-border min-h-[300px] shadow-calendar">
|
|
220
|
+
<div class="flex flex-col space-y-2 items-start p-3 border-r border-border">
|
|
221
221
|
{#each periods as period}
|
|
222
222
|
<button
|
|
223
223
|
onclick={period.action}
|
|
224
224
|
class="{selectedPeriod === period.slug
|
|
225
|
-
? 'selected-period text-
|
|
226
|
-
: 'text-
|
|
225
|
+
? 'selected-period text-foreground-selected bg-background-selected font-medium'
|
|
226
|
+
: 'text-foreground-default-secondary'} whitespace-nowrap text-base px-2 py-1 tracking-normal rounded-md cursor-pointer"
|
|
227
227
|
>
|
|
228
228
|
{period.label}
|
|
229
229
|
</button>
|
|
@@ -232,8 +232,10 @@
|
|
|
232
232
|
<RangeCalendar bind:value numberOfMonths={2} />
|
|
233
233
|
</div>
|
|
234
234
|
<div class="p-3 flex justify-end items-center space-x-3">
|
|
235
|
-
<BaseButton variant="secondary" onclick={cancel}>Cancel</BaseButton>
|
|
236
|
-
<BaseButton variant="primary" onclick={confirm} disabled={!value.end}
|
|
235
|
+
<BaseButton variant="secondary" size="lg" onclick={cancel}>Cancel</BaseButton>
|
|
236
|
+
<BaseButton variant="primary" size="lg" onclick={confirm} disabled={!value.end}
|
|
237
|
+
>Confirm</BaseButton
|
|
238
|
+
>
|
|
237
239
|
</div>
|
|
238
240
|
</div>
|
|
239
241
|
</Transition>
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
import type { DrawerContextProps, DrawerOption } from './types.ts'
|
|
3
3
|
import DrawerContextItem from './DrawerContextItem.svelte'
|
|
4
4
|
import DrawerContextSeparator from './DrawerContextSeparator.svelte'
|
|
5
|
+
import EmptyState from './EmptyState.svelte'
|
|
6
|
+
import BaseCounter from './BaseCounter.svelte'
|
|
7
|
+
import { Icon } from '@steeze-ui/svelte-icon'
|
|
8
|
+
import { ChevronRight } from '@steeze-ui/heroicons'
|
|
9
|
+
import { slide } from 'svelte/transition'
|
|
5
10
|
|
|
6
11
|
let {
|
|
7
12
|
items = $bindable([]),
|
|
@@ -9,10 +14,44 @@
|
|
|
9
14
|
widthClass = 'w-60',
|
|
10
15
|
onclick,
|
|
11
16
|
onselect,
|
|
12
|
-
children
|
|
17
|
+
children,
|
|
18
|
+
groups
|
|
13
19
|
}: DrawerContextProps = $props()
|
|
14
20
|
|
|
15
21
|
let selectedItems = $derived(items.filter((i) => i.selected))
|
|
22
|
+
let hasGroups = $derived(groups && groups.length > 0)
|
|
23
|
+
let { groupedItems, ungroupedItems } = $derived.by(() => {
|
|
24
|
+
if (!hasGroups) return { groupedItems: new Map(), ungroupedItems: items }
|
|
25
|
+
|
|
26
|
+
const grouped = new Map<string, DrawerOption[]>()
|
|
27
|
+
const ungrouped: DrawerOption[] = []
|
|
28
|
+
|
|
29
|
+
groups!.forEach((group) => {
|
|
30
|
+
grouped.set(group.slug, [])
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
items.forEach((item) => {
|
|
34
|
+
if (item.groupBy && grouped.has(item.groupBy)) {
|
|
35
|
+
grouped.get(item.groupBy)!.push(item)
|
|
36
|
+
} else {
|
|
37
|
+
ungrouped.push(item)
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
return { groupedItems: grouped, ungroupedItems: ungrouped }
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
let openGroups = $state<Record<string, boolean>>({})
|
|
45
|
+
|
|
46
|
+
$effect(() => {
|
|
47
|
+
if (hasGroups) {
|
|
48
|
+
const selectedItem = items.find((i) => i.selected)
|
|
49
|
+
if (selectedItem?.groupBy && Object.keys(openGroups).length === 0) {
|
|
50
|
+
openGroups = { [selectedItem.groupBy]: true }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
16
55
|
$effect(() => {
|
|
17
56
|
onselect?.(selectedItems)
|
|
18
57
|
})
|
|
@@ -23,19 +62,83 @@
|
|
|
23
62
|
return i
|
|
24
63
|
})
|
|
25
64
|
}
|
|
65
|
+
|
|
66
|
+
function toggleGroup(groupSlug: string) {
|
|
67
|
+
openGroups = openGroups[groupSlug] ? {} : { [groupSlug]: true }
|
|
68
|
+
}
|
|
26
69
|
</script>
|
|
27
70
|
|
|
71
|
+
{#snippet drawerItem(item: DrawerOption)}
|
|
72
|
+
{#if item.separator}
|
|
73
|
+
<DrawerContextSeparator />
|
|
74
|
+
{:else}
|
|
75
|
+
<div class:px-1={!item.groupBy}>
|
|
76
|
+
<DrawerContextItem {item} {multiple} {onclick} onchange={updateItem} />
|
|
77
|
+
</div>
|
|
78
|
+
{/if}
|
|
79
|
+
{/snippet}
|
|
80
|
+
|
|
28
81
|
<div
|
|
29
|
-
class="{widthClass} border border-
|
|
82
|
+
class="{widthClass} border border-border rounded-2xl shadow-lg bg-white overflow-hidden flex flex-col py-1 max-h-[400px] overflow-y-auto"
|
|
30
83
|
>
|
|
31
84
|
{@render children?.()}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
85
|
+
|
|
86
|
+
{#if hasGroups}
|
|
87
|
+
{#each groups as group, index}
|
|
88
|
+
{@const groupItems = groupedItems.get(group.slug) || []}
|
|
89
|
+
{@const isLastGroup = index === groups!.length - 1}
|
|
90
|
+
<div class="flex-shrink-0 px-1">
|
|
91
|
+
<button
|
|
92
|
+
class="cursor-pointer flex items-center justify-between h-8 pl-2.5 pr-2.5 py-2.5 text-base font-medium text-foreground-default-secondary w-full hover:bg-background-default-secondary rounded-lg overflow-clip"
|
|
93
|
+
onclick={() => toggleGroup(group.slug)}
|
|
94
|
+
>
|
|
95
|
+
<div class="flex items-center gap-1.5">
|
|
96
|
+
<span>{group.label}</span>
|
|
97
|
+
<Icon
|
|
98
|
+
src={ChevronRight}
|
|
99
|
+
class="size-3 text-icon-default-secondary transition-all transform {openGroups[
|
|
100
|
+
group.slug
|
|
101
|
+
]
|
|
102
|
+
? 'rotate-90'
|
|
103
|
+
: ''}"
|
|
104
|
+
/>
|
|
105
|
+
</div>
|
|
106
|
+
{#if groupItems.length}
|
|
107
|
+
<BaseCounter value={groupItems.length} />
|
|
108
|
+
{/if}
|
|
109
|
+
</button>
|
|
110
|
+
|
|
111
|
+
{#if openGroups[group.slug]}
|
|
112
|
+
<div transition:slide class="w-full">
|
|
113
|
+
{#if !groupItems.length}
|
|
114
|
+
<div class="px-1 pt-1 pb-5">
|
|
115
|
+
<EmptyState
|
|
116
|
+
iconSource={group.emptyIcon}
|
|
117
|
+
title={group.emptyTitle || 'No items here'}
|
|
118
|
+
description={group.emptyDescription || 'Add items to get started'}
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
{:else}
|
|
122
|
+
<div class="max-h-[400px] overflow-y-auto">
|
|
123
|
+
{#each groupItems as item}
|
|
124
|
+
{@render drawerItem(item)}
|
|
125
|
+
{/each}
|
|
126
|
+
</div>
|
|
127
|
+
{/if}
|
|
128
|
+
</div>
|
|
129
|
+
{/if}
|
|
130
|
+
</div>
|
|
131
|
+
{#if !isLastGroup}
|
|
35
132
|
<DrawerContextSeparator />
|
|
36
|
-
{:else}
|
|
37
|
-
<DrawerContextItem {item} {multiple} {onclick} onchange={updateItem} />
|
|
38
133
|
{/if}
|
|
39
134
|
{/each}
|
|
40
|
-
|
|
135
|
+
{/if}
|
|
136
|
+
|
|
137
|
+
{#if ungroupedItems.length}
|
|
138
|
+
<div class="flex-shrink-0">
|
|
139
|
+
{#each ungroupedItems as item}
|
|
140
|
+
{@render drawerItem(item)}
|
|
141
|
+
{/each}
|
|
142
|
+
</div>
|
|
143
|
+
{/if}
|
|
41
144
|
</div>
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
import InputCheckbox from './InputCheckbox.svelte'
|
|
4
4
|
import { Icon } from '@steeze-ui/svelte-icon'
|
|
5
5
|
import { onMount } from 'svelte'
|
|
6
|
-
import { Success
|
|
7
|
-
import ProfileAvatar from './ProfileAvatar.svelte'
|
|
6
|
+
import { Success } from '@invopop/ui-icons'
|
|
8
7
|
import clsx from 'clsx'
|
|
9
8
|
import BaseFlag from './BaseFlag.svelte'
|
|
10
9
|
import { getCountryName } from './helpers.js'
|
|
@@ -14,32 +13,24 @@
|
|
|
14
13
|
multiple = false,
|
|
15
14
|
item = $bindable(),
|
|
16
15
|
scrollIfSelected = false,
|
|
17
|
-
workspace = false,
|
|
18
16
|
onchange,
|
|
19
17
|
onclick
|
|
20
18
|
}: DrawerContextItemProps = $props()
|
|
21
19
|
|
|
22
20
|
let el: HTMLElement | undefined = $state()
|
|
23
21
|
|
|
24
|
-
let hasIcon = $derived(item.icon || workspace)
|
|
25
|
-
|
|
26
22
|
let styles = $derived(
|
|
27
23
|
clsx(
|
|
28
|
-
|
|
29
|
-
{ '
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
'px-2 py-1.5 space-x-1.5',
|
|
25
|
+
{ 'bg-background-selected': item.selected && !multiple },
|
|
26
|
+
{
|
|
27
|
+
'group-hover:bg-background-default-secondary':
|
|
28
|
+
(!item.selected && !item.disabled) || multiple
|
|
29
|
+
}
|
|
34
30
|
)
|
|
35
31
|
)
|
|
36
32
|
let labelStyles = $derived(
|
|
37
|
-
clsx(
|
|
38
|
-
{ 'text-danger-500': item.destructive },
|
|
39
|
-
{ 'text-neutral-800': !item.destructive },
|
|
40
|
-
{ 'tracking-tight max-w-[200px]': workspace },
|
|
41
|
-
{ 'tracking-normal': !workspace }
|
|
42
|
-
)
|
|
33
|
+
clsx({ 'text-danger-500': item.destructive }, { 'text-neutral-800': !item.destructive })
|
|
43
34
|
)
|
|
44
35
|
let title = $derived(item.label.length > 25 ? item.label : undefined)
|
|
45
36
|
|
|
@@ -64,19 +55,15 @@
|
|
|
64
55
|
|
|
65
56
|
<button
|
|
66
57
|
bind:this={el}
|
|
67
|
-
class="cursor-pointer w-full
|
|
58
|
+
class="cursor-pointer w-full disabled:opacity-30 group"
|
|
68
59
|
disabled={item.disabled}
|
|
69
60
|
onclick={handleClick}
|
|
70
61
|
>
|
|
71
|
-
<div class="{styles} rounded pr-2 flex items-center justify-start w-full">
|
|
72
|
-
{#if
|
|
73
|
-
<ProfileAvatar name={item.label} picture={item.picture} large />
|
|
74
|
-
{:else if item.icon}
|
|
62
|
+
<div class="{styles} rounded-md pr-2 flex items-center justify-start w-full">
|
|
63
|
+
{#if item.icon}
|
|
75
64
|
<Icon
|
|
76
65
|
src={item.icon}
|
|
77
|
-
class="w-4 h-4 {item.destructive
|
|
78
|
-
? 'text-danger-500'
|
|
79
|
-
: item.iconClass || 'text-neutral-500'}"
|
|
66
|
+
class="w-4 h-4 {item.destructive ? 'text-icon-critical' : item.iconClass || 'text-icon'}"
|
|
80
67
|
/>
|
|
81
68
|
{/if}
|
|
82
69
|
<div class="whitespace-nowrap flex-1 text-left flex flex-col truncate" {title}>
|
|
@@ -90,7 +77,7 @@
|
|
|
90
77
|
{#if item.country}
|
|
91
78
|
<span class="flex space-x-1 items-center">
|
|
92
79
|
<BaseFlag country={item.country} width={10} />
|
|
93
|
-
<span class="text-sm text-
|
|
80
|
+
<span class="text-sm text-foreground-default-secondary">
|
|
94
81
|
{getCountryName(item.country)}
|
|
95
82
|
</span>
|
|
96
83
|
</span>
|
|
@@ -98,15 +85,16 @@
|
|
|
98
85
|
</div>
|
|
99
86
|
{#if multiple}
|
|
100
87
|
<InputCheckbox
|
|
101
|
-
|
|
102
|
-
onchange={() => {
|
|
88
|
+
checked={item.selected ?? false}
|
|
89
|
+
onchange={(value) => {
|
|
90
|
+
item.selected = value
|
|
103
91
|
onchange?.(item)
|
|
104
92
|
}}
|
|
105
93
|
/>
|
|
106
94
|
{:else if item.selected}
|
|
107
|
-
<Icon src={Success} class="
|
|
95
|
+
<Icon src={Success} class="size-4 text-icon-selected" />
|
|
108
96
|
{:else if item.rightIcon}
|
|
109
|
-
<Icon src={item.rightIcon} class="
|
|
97
|
+
<Icon src={item.rightIcon} class="size-4 text-icon-default-secondary" />
|
|
110
98
|
{/if}
|
|
111
99
|
</div>
|
|
112
100
|
</button>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<li class="bg-
|
|
1
|
+
<li class="bg-border h-px w-full my-1"></li>
|