@licklist/design 0.78.5-dev.59 → 0.78.5-dev.60
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/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/v2/components/Button/Button.scss.js +1 -1
- package/dist/v2/components/Checkbox/Checkbox.scss.js +1 -1
- package/dist/v2/components/IconButton/IconButton.d.ts +9 -0
- package/dist/v2/components/IconButton/IconButton.d.ts.map +1 -0
- package/dist/v2/components/IconButton/IconButton.js +137 -0
- package/dist/v2/components/IconButton/IconButton.scss.js +6 -0
- package/dist/v2/components/IconButton/index.d.ts +3 -0
- package/dist/v2/components/IconButton/index.d.ts.map +1 -0
- package/dist/v2/components/NewInput/NewInput.d.ts.map +1 -1
- package/dist/v2/components/NewInput/NewInput.js +4 -3
- package/dist/v2/components/ZoneCard/AddResourceButton.d.ts +8 -0
- package/dist/v2/components/ZoneCard/AddResourceButton.d.ts.map +1 -0
- package/dist/v2/components/ZoneCard/AddResourceButton.js +17 -0
- package/dist/v2/components/ZoneCard/ResourceRow.d.ts +17 -0
- package/dist/v2/components/ZoneCard/ResourceRow.d.ts.map +1 -0
- package/dist/v2/components/ZoneCard/ResourceRow.js +127 -0
- package/dist/v2/components/ZoneCard/ZoneCard.d.ts +26 -0
- package/dist/v2/components/ZoneCard/ZoneCard.d.ts.map +1 -0
- package/dist/v2/components/ZoneCard/ZoneCard.js +44 -0
- package/dist/v2/components/ZoneCard/ZoneCard.scss.js +6 -0
- package/dist/v2/components/ZoneCard/ZoneContainer.d.ts +12 -0
- package/dist/v2/components/ZoneCard/ZoneContainer.d.ts.map +1 -0
- package/dist/v2/components/ZoneCard/ZoneContainer.js +16 -0
- package/dist/v2/components/ZoneCard/ZoneHeader.d.ts +15 -0
- package/dist/v2/components/ZoneCard/ZoneHeader.d.ts.map +1 -0
- package/dist/v2/components/ZoneCard/ZoneHeader.js +102 -0
- package/dist/v2/components/ZoneCard/index.d.ts +11 -0
- package/dist/v2/components/ZoneCard/index.d.ts.map +1 -0
- package/dist/v2/components/index.d.ts +5 -1
- package/dist/v2/components/index.d.ts.map +1 -1
- package/dist/v2/icons/index.d.ts +16 -0
- package/dist/v2/icons/index.d.ts.map +1 -1
- package/dist/v2/icons/index.js +57 -1
- package/dist/v2/index.d.ts +10 -0
- package/dist/v2/index.d.ts.map +1 -1
- package/dist/v2/pages/Settings/components/SidebarCustomisation.js +5 -0
- package/dist/v2/pages/Settings/components/SidebarNavItem.js +5 -0
- package/dist/v2/pages/ZonesResources/ZonesResourcesPage.d.ts +12 -0
- package/dist/v2/pages/ZonesResources/ZonesResourcesPage.d.ts.map +1 -0
- package/dist/v2/pages/ZonesResources/ZonesResourcesPage.js +43 -0
- package/dist/v2/pages/ZonesResources/ZonesResourcesPage.scss.js +6 -0
- package/dist/v2/pages/ZonesResources/index.d.ts +3 -0
- package/dist/v2/pages/ZonesResources/index.d.ts.map +1 -0
- package/dist/v2/styles/components/Button.scss +1 -0
- package/dist/v2/styles/form/NewInput.scss +10 -6
- package/dist/v2/styles/form/NewInput.scss.js +1 -1
- package/package.json +1 -1
- package/src/index.ts +3 -1
- package/src/v2/components/ActionMenu/ActionMenu.stories.tsx +58 -0
- package/src/v2/components/ActionMenu/ActionMenu.tsx +1 -1
- package/src/v2/components/Checkbox/Checkbox.scss +1 -1
- package/src/v2/components/IconButton/IconButton.scss +75 -0
- package/src/v2/components/IconButton/IconButton.stories.tsx +51 -0
- package/src/v2/components/IconButton/IconButton.tsx +50 -0
- package/src/v2/components/IconButton/index.ts +2 -0
- package/src/v2/components/NewInput/NewInput.tsx +2 -1
- package/src/v2/components/NewPageHeader/NewPageHeader.stories.tsx +28 -0
- package/src/v2/components/ZoneCard/AddResourceButton.tsx +20 -0
- package/src/v2/components/ZoneCard/ResourceRow.tsx +64 -0
- package/src/v2/components/ZoneCard/ZoneCard.scss +142 -0
- package/src/v2/components/ZoneCard/ZoneCard.stories.tsx +140 -0
- package/src/v2/components/ZoneCard/ZoneCard.tsx +72 -0
- package/src/v2/components/ZoneCard/ZoneContainer.tsx +26 -0
- package/src/v2/components/ZoneCard/ZoneHeader.tsx +45 -0
- package/src/v2/components/ZoneCard/index.ts +14 -0
- package/src/v2/components/index.ts +11 -1
- package/src/v2/icons/index.tsx +24 -0
- package/src/v2/index.ts +21 -0
- package/src/v2/pages/ZonesResources/ZonesResourcesPage.scss +22 -0
- package/src/v2/pages/ZonesResources/ZonesResourcesPage.stories.tsx +46 -0
- package/src/v2/pages/ZonesResources/ZonesResourcesPage.tsx +45 -0
- package/src/v2/pages/ZonesResources/index.ts +2 -0
- package/src/v2/styles/components/Button.scss +1 -0
- package/src/v2/styles/form/NewInput.scss +10 -6
package/src/index.ts
CHANGED
|
@@ -29,7 +29,8 @@ export * from './report'
|
|
|
29
29
|
export * from './venue-map-sets'
|
|
30
30
|
export * from './affiliate'
|
|
31
31
|
export * from './typeahead-helper'
|
|
32
|
-
export
|
|
32
|
+
export { ZoneForm } from './zone/form'
|
|
33
|
+
export type { ZoneFormProps } from './zone/form'
|
|
33
34
|
export * from './resource'
|
|
34
35
|
export * from './virtualized'
|
|
35
36
|
export * from './customers'
|
|
@@ -49,4 +50,5 @@ export * from './UnderMaintenance'
|
|
|
49
50
|
export * from './v2/dashboard-analytics'
|
|
50
51
|
export * from './v2/navigation/DashboardLayout'
|
|
51
52
|
export * from './v2/pages/Settings'
|
|
53
|
+
export * from './v2/pages/ZonesResources'
|
|
52
54
|
export * from './v2/components'
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Meta, StoryObj } from '@storybook/react'
|
|
3
|
+
import { ActionMenu } from './ActionMenu'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'v2/Components/ActionMenu',
|
|
7
|
+
component: ActionMenu,
|
|
8
|
+
} as Meta<typeof ActionMenu>
|
|
9
|
+
|
|
10
|
+
type Story = StoryObj<typeof ActionMenu>
|
|
11
|
+
|
|
12
|
+
const defaultItems = [
|
|
13
|
+
{ label: 'Edit', onClick: () => console.log('Edit') },
|
|
14
|
+
{ label: 'Duplicate', onClick: () => console.log('Duplicate') },
|
|
15
|
+
{ label: 'Delete', onClick: () => console.log('Delete'), variant: 'danger' as const },
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
export const Default: Story = {
|
|
19
|
+
args: {
|
|
20
|
+
items: defaultItems,
|
|
21
|
+
},
|
|
22
|
+
decorators: [
|
|
23
|
+
(Story) => (
|
|
24
|
+
<div style={{ display: 'flex', justifyContent: 'flex-end', paddingTop: 200 }}>
|
|
25
|
+
<Story />
|
|
26
|
+
</div>
|
|
27
|
+
),
|
|
28
|
+
],
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const OpenDown: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
items: defaultItems,
|
|
34
|
+
direction: 'down',
|
|
35
|
+
},
|
|
36
|
+
decorators: [
|
|
37
|
+
(Story) => (
|
|
38
|
+
<div style={{ display: 'flex', justifyContent: 'flex-end', paddingTop: 20 }}>
|
|
39
|
+
<Story />
|
|
40
|
+
</div>
|
|
41
|
+
),
|
|
42
|
+
],
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const WithCustomIconColour: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
items: defaultItems,
|
|
48
|
+
iconColour: '#E0423A',
|
|
49
|
+
direction: 'down',
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const SingleItem: Story = {
|
|
54
|
+
args: {
|
|
55
|
+
items: [{ label: 'Edit', onClick: () => console.log('Edit') }],
|
|
56
|
+
direction: 'down',
|
|
57
|
+
},
|
|
58
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
.icon-button {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: var(--spacing-sm, 8px);
|
|
5
|
+
padding: 0 16px 0 12px;
|
|
6
|
+
height: 34px;
|
|
7
|
+
background: transparent;
|
|
8
|
+
border: 1px solid var(--border-primary);
|
|
9
|
+
border-radius: 8px;
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
transition: all 0.2s ease;
|
|
12
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
13
|
+
|
|
14
|
+
&:hover {
|
|
15
|
+
background: var(--surface-secondary);
|
|
16
|
+
color: var(--label-primary);
|
|
17
|
+
|
|
18
|
+
.icon-button__icon {
|
|
19
|
+
color: var(--label-primary);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.icon-button__label {
|
|
23
|
+
color: var(--label-primary);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&:active {
|
|
28
|
+
background: var(--surface-tertiary);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&__icon {
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
color: var(--label-primary);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&__label {
|
|
38
|
+
font-size: 13px;
|
|
39
|
+
font-weight: 500;
|
|
40
|
+
line-height: 16px;
|
|
41
|
+
color: var(--label-primary);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Icon-only variant (no label)
|
|
46
|
+
.icon-button--icon-only {
|
|
47
|
+
display: inline-flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
justify-content: center;
|
|
50
|
+
width: 32px;
|
|
51
|
+
height: 32px;
|
|
52
|
+
border: 1px solid var(--border-primary);
|
|
53
|
+
border-radius: 8px;
|
|
54
|
+
background: transparent;
|
|
55
|
+
color: var(--label-primary);
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
transition: all 0.2s ease;
|
|
58
|
+
|
|
59
|
+
&:hover {
|
|
60
|
+
background: var(--surface-primary, #fff);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&:active {
|
|
64
|
+
background: var(--surface-tertiary);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Danger variant
|
|
69
|
+
.icon-button--danger {
|
|
70
|
+
color: var(--label-danger, #cc3c35);
|
|
71
|
+
|
|
72
|
+
&:hover {
|
|
73
|
+
background: var(--surface-primary, #fff);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Meta, StoryObj } from '@storybook/react'
|
|
3
|
+
import { IconButton } from './IconButton'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'v2/Components/IconButton',
|
|
7
|
+
component: IconButton,
|
|
8
|
+
} as Meta<typeof IconButton>
|
|
9
|
+
|
|
10
|
+
type Story = StoryObj<typeof IconButton>
|
|
11
|
+
|
|
12
|
+
export const BackWithLabel: Story = {
|
|
13
|
+
args: {
|
|
14
|
+
label: 'Go Back',
|
|
15
|
+
icon: 'back',
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const AddWithLabel: Story = {
|
|
20
|
+
args: {
|
|
21
|
+
label: 'Add Item',
|
|
22
|
+
icon: 'add',
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const DeleteWithLabel: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
label: 'Remove Item',
|
|
29
|
+
icon: 'delete',
|
|
30
|
+
variant: 'danger',
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const IconOnlyBack: Story = {
|
|
35
|
+
args: {
|
|
36
|
+
icon: 'back',
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const IconOnlyAdd: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
icon: 'add',
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const IconOnlyDelete: Story = {
|
|
47
|
+
args: {
|
|
48
|
+
icon: 'delete',
|
|
49
|
+
variant: 'danger',
|
|
50
|
+
},
|
|
51
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ButtonHTMLAttributes, ReactNode } from 'react'
|
|
2
|
+
import { ArrowLeftIcon, PlusIcon, DeleteIcon } from '../../icons'
|
|
3
|
+
import './IconButton.scss'
|
|
4
|
+
|
|
5
|
+
export interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
6
|
+
label?: string
|
|
7
|
+
icon?: 'back' | 'add' | 'delete' | ReactNode
|
|
8
|
+
variant?: 'default' | 'danger'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function IconButton({
|
|
12
|
+
label,
|
|
13
|
+
icon = 'back',
|
|
14
|
+
variant = 'default',
|
|
15
|
+
className = '',
|
|
16
|
+
...props
|
|
17
|
+
}: IconButtonProps) {
|
|
18
|
+
const isIconOnly = !label
|
|
19
|
+
const classes = [
|
|
20
|
+
isIconOnly ? 'icon-button--icon-only' : 'icon-button',
|
|
21
|
+
variant === 'danger' ? 'icon-button--danger' : '',
|
|
22
|
+
className,
|
|
23
|
+
].filter(Boolean).join(' ')
|
|
24
|
+
|
|
25
|
+
const iconSize = isIconOnly ? 32 : 16
|
|
26
|
+
|
|
27
|
+
const renderIcon = () => {
|
|
28
|
+
if (icon === 'back') return ArrowLeftIcon({ width: iconSize, height: iconSize })
|
|
29
|
+
if (icon === 'add') return PlusIcon({ width: iconSize, height: iconSize })
|
|
30
|
+
if (icon === 'delete') return DeleteIcon({ width: iconSize, height: iconSize })
|
|
31
|
+
return icon
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (isIconOnly) {
|
|
35
|
+
return (
|
|
36
|
+
<button type="button" className={classes} {...props}>
|
|
37
|
+
{renderIcon()}
|
|
38
|
+
</button>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<button className={classes} {...props}>
|
|
44
|
+
<span className="icon-button__icon">
|
|
45
|
+
{renderIcon()}
|
|
46
|
+
</span>
|
|
47
|
+
<span className="icon-button__label">{label}</span>
|
|
48
|
+
</button>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -94,7 +94,8 @@ export const NewInput = forwardRef<HTMLInputElement | HTMLTextAreaElement, NewIn
|
|
|
94
94
|
<div className={containerClasses}>
|
|
95
95
|
{(label || optional) && (
|
|
96
96
|
<label className="new-form-input__label">
|
|
97
|
-
{label}
|
|
97
|
+
<span>{label}</span>
|
|
98
|
+
{optional && <span className="new-form-input__label-optional">(optional)</span>}
|
|
98
99
|
</label>
|
|
99
100
|
)}
|
|
100
101
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
2
|
import { NewPageHeader } from './NewPageHeader'
|
|
3
|
+
import { Button, ButtonText } from '../Button'
|
|
3
4
|
|
|
4
5
|
const meta: Meta<typeof NewPageHeader> = {
|
|
5
6
|
title: 'V2/Components/NewPageHeader',
|
|
@@ -42,3 +43,30 @@ export const CustomCancelLabel: Story = {
|
|
|
42
43
|
onCancel: () => alert('Go Back clicked'),
|
|
43
44
|
},
|
|
44
45
|
}
|
|
46
|
+
|
|
47
|
+
export const WithAction: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
title: 'Zones & Resources',
|
|
50
|
+
renderRight: () => (
|
|
51
|
+
<Button variant="primary" onClick={() => alert('Add Zone clicked')}>
|
|
52
|
+
<ButtonText color="white">+ Add Zone</ButtonText>
|
|
53
|
+
</Button>
|
|
54
|
+
),
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const WithMultipleActions: Story = {
|
|
59
|
+
args: {
|
|
60
|
+
title: 'Zones & Resources',
|
|
61
|
+
renderRight: () => (
|
|
62
|
+
<>
|
|
63
|
+
<Button variant="secondary" onClick={() => alert('Export clicked')}>
|
|
64
|
+
<ButtonText color="action">Export</ButtonText>
|
|
65
|
+
</Button>
|
|
66
|
+
<Button variant="primary" onClick={() => alert('Add Zone clicked')}>
|
|
67
|
+
<ButtonText color="white">+ Add Zone</ButtonText>
|
|
68
|
+
</Button>
|
|
69
|
+
</>
|
|
70
|
+
),
|
|
71
|
+
},
|
|
72
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { IconButton } from '../IconButton'
|
|
3
|
+
|
|
4
|
+
export interface AddResourceButtonProps {
|
|
5
|
+
label?: string
|
|
6
|
+
onClick: () => void
|
|
7
|
+
className?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const AddResourceButton: React.FC<AddResourceButtonProps> = ({
|
|
11
|
+
label = 'Add Resource',
|
|
12
|
+
onClick,
|
|
13
|
+
className = '',
|
|
14
|
+
}) => {
|
|
15
|
+
return (
|
|
16
|
+
<div className={`zone-card__add-resource-wrapper ${className}`}>
|
|
17
|
+
<IconButton label={label} icon='add' onClick={onClick} />
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { ActionMenu, ActionMenuItem } from '../ActionMenu'
|
|
3
|
+
import { GripVerticalIcon } from '../../icons'
|
|
4
|
+
import { DragHandleProps } from './ZoneContainer'
|
|
5
|
+
import './ZoneCard.scss'
|
|
6
|
+
|
|
7
|
+
export interface ResourceRowProps {
|
|
8
|
+
name: string
|
|
9
|
+
quantity: number
|
|
10
|
+
capacity: number
|
|
11
|
+
menuItems?: ActionMenuItem[]
|
|
12
|
+
draggable?: boolean
|
|
13
|
+
dragHandleProps?: DragHandleProps
|
|
14
|
+
onClick?: () => void
|
|
15
|
+
className?: string
|
|
16
|
+
style?: React.CSSProperties
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const ResourceRow = React.forwardRef<HTMLDivElement, ResourceRowProps>(({
|
|
20
|
+
name,
|
|
21
|
+
quantity,
|
|
22
|
+
capacity,
|
|
23
|
+
menuItems = [],
|
|
24
|
+
draggable = true,
|
|
25
|
+
dragHandleProps,
|
|
26
|
+
onClick,
|
|
27
|
+
className = '',
|
|
28
|
+
style,
|
|
29
|
+
}, ref) => {
|
|
30
|
+
const classes = [
|
|
31
|
+
'zone-card__resource',
|
|
32
|
+
onClick ? 'zone-card__resource--clickable' : '',
|
|
33
|
+
className,
|
|
34
|
+
].filter(Boolean).join(' ')
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div ref={ref} className={classes} style={style} onClick={onClick}>
|
|
38
|
+
{draggable && (
|
|
39
|
+
<div
|
|
40
|
+
className="zone-card__drag-handle zone-card__drag-handle--resource"
|
|
41
|
+
{...dragHandleProps}
|
|
42
|
+
onClick={(e) => e.stopPropagation()}
|
|
43
|
+
>
|
|
44
|
+
{GripVerticalIcon({ width: 14, height: 14 })}
|
|
45
|
+
</div>
|
|
46
|
+
)}
|
|
47
|
+
<span className="zone-card__resource-name">{name}</span>
|
|
48
|
+
<div className="zone-card__resource-stats">
|
|
49
|
+
<span className="zone-card__resource-stat">Qty: {quantity}</span>
|
|
50
|
+
<span className="zone-card__resource-stat">Cap: {capacity}</span>
|
|
51
|
+
<span className="zone-card__resource-stat zone-card__resource-stat--total">
|
|
52
|
+
Total: {quantity * capacity}
|
|
53
|
+
</span>
|
|
54
|
+
</div>
|
|
55
|
+
{menuItems.length > 0 && (
|
|
56
|
+
<div className="zone-card__resource-actions" onClick={(e) => e.stopPropagation()}>
|
|
57
|
+
<ActionMenu items={menuItems} />
|
|
58
|
+
</div>
|
|
59
|
+
)}
|
|
60
|
+
</div>
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
ResourceRow.displayName = 'ResourceRow'
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
.zone-card {
|
|
2
|
+
border: 1px solid var(--border-primary);
|
|
3
|
+
border-radius: 8px;
|
|
4
|
+
overflow: visible;
|
|
5
|
+
background: var(--surface-primary);
|
|
6
|
+
|
|
7
|
+
&__header {
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
gap: 12px;
|
|
11
|
+
padding: 12px 16px;
|
|
12
|
+
background: var(--surface-secondary);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&__drag-handle {
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
padding: 4px;
|
|
19
|
+
border-radius: 4px;
|
|
20
|
+
cursor: grab;
|
|
21
|
+
color: var(--label-secondary);
|
|
22
|
+
transition: all 0.2s ease;
|
|
23
|
+
|
|
24
|
+
&:hover {
|
|
25
|
+
color: var(--label-primary);
|
|
26
|
+
background: var(--surface-primary);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&:active {
|
|
30
|
+
cursor: grabbing;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&--resource {
|
|
34
|
+
color: var(--label-secondary);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&__name {
|
|
39
|
+
flex: 1;
|
|
40
|
+
min-width: 0;
|
|
41
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
42
|
+
font-size: 15px;
|
|
43
|
+
font-weight: 600;
|
|
44
|
+
line-height: 20px;
|
|
45
|
+
color: var(--label-primary);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&__header-right {
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
gap: 12px;
|
|
52
|
+
flex-shrink: 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&__total {
|
|
56
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
57
|
+
font-size: 13px;
|
|
58
|
+
font-weight: 400;
|
|
59
|
+
line-height: 16px;
|
|
60
|
+
color: var(--label-secondary);
|
|
61
|
+
white-space: nowrap;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Resource rows
|
|
65
|
+
&__resource {
|
|
66
|
+
display: flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
gap: 12px;
|
|
69
|
+
padding: 10px 16px 10px 32px;
|
|
70
|
+
border-top: 1px solid var(--border-primary);
|
|
71
|
+
transition: background 0.2s ease;
|
|
72
|
+
|
|
73
|
+
&--clickable {
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
|
|
76
|
+
&:hover {
|
|
77
|
+
background: var(--surface-secondary);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
&__resource-name {
|
|
83
|
+
flex: 1;
|
|
84
|
+
min-width: 0;
|
|
85
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
86
|
+
font-size: 15px;
|
|
87
|
+
font-weight: 400;
|
|
88
|
+
line-height: 20px;
|
|
89
|
+
color: var(--label-primary);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&__resource-stats {
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
gap: 32px;
|
|
96
|
+
flex-shrink: 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&__resource-stat {
|
|
100
|
+
font-family: var(--font-family-sans, 'Geist', sans-serif);
|
|
101
|
+
font-size: 13px;
|
|
102
|
+
font-weight: 400;
|
|
103
|
+
line-height: 16px;
|
|
104
|
+
color: var(--label-secondary);
|
|
105
|
+
white-space: nowrap;
|
|
106
|
+
min-width: 56px;
|
|
107
|
+
|
|
108
|
+
&--total {
|
|
109
|
+
min-width: 56px;
|
|
110
|
+
text-align: right;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&__resource-actions {
|
|
115
|
+
flex-shrink: 0;
|
|
116
|
+
width: 32px;
|
|
117
|
+
display: flex;
|
|
118
|
+
justify-content: flex-end;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Add resource button wrapper
|
|
122
|
+
&__add-resource-wrapper {
|
|
123
|
+
padding: 12px 16px;
|
|
124
|
+
border-top: 1px solid var(--border-primary);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@media (max-width: 768px) {
|
|
129
|
+
.zone-card {
|
|
130
|
+
&__resource {
|
|
131
|
+
padding-left: 16px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&__resource-stats {
|
|
135
|
+
gap: 16px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&__resource-stat {
|
|
139
|
+
min-width: auto;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Meta, StoryObj } from '@storybook/react'
|
|
3
|
+
import { ZoneCard } from './ZoneCard'
|
|
4
|
+
import { ZoneContainer } from './ZoneContainer'
|
|
5
|
+
import { ZoneHeader } from './ZoneHeader'
|
|
6
|
+
import { ResourceRow } from './ResourceRow'
|
|
7
|
+
import { AddResourceButton } from './AddResourceButton'
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'v2/Components/ZoneCard',
|
|
11
|
+
component: ZoneCard,
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: 'padded',
|
|
14
|
+
},
|
|
15
|
+
} as Meta<typeof ZoneCard>
|
|
16
|
+
|
|
17
|
+
type Story = StoryObj<typeof ZoneCard>
|
|
18
|
+
|
|
19
|
+
const zoneMenuItems = [
|
|
20
|
+
{ label: 'Edit Zone', onClick: () => alert('Edit Zone') },
|
|
21
|
+
{ label: 'Delete Zone', onClick: () => alert('Delete Zone'), variant: 'danger' as const },
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
const resourceMenuItems = [
|
|
25
|
+
{ label: 'Edit Resource', onClick: () => alert('Edit Resource') },
|
|
26
|
+
{ label: 'Delete Resource', onClick: () => alert('Delete Resource'), variant: 'danger' as const },
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
// Composed ZoneCard (all-in-one)
|
|
30
|
+
export const Default: Story = {
|
|
31
|
+
args: {
|
|
32
|
+
name: 'Bowling',
|
|
33
|
+
status: 'active',
|
|
34
|
+
totalCapacity: 2,
|
|
35
|
+
menuItems: zoneMenuItems,
|
|
36
|
+
onAddResource: () => alert('Add Resource'),
|
|
37
|
+
resources: [
|
|
38
|
+
{ id: '1', name: 'Table', quantity: 1, capacity: 1, menuItems: resourceMenuItems },
|
|
39
|
+
{ id: '2', name: 'Lane', quantity: 1, capacity: 1, menuItems: resourceMenuItems },
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const DisabledZone: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
name: 'VIP Lounge',
|
|
47
|
+
status: 'disabled',
|
|
48
|
+
totalCapacity: 0,
|
|
49
|
+
menuItems: zoneMenuItems,
|
|
50
|
+
onAddResource: () => alert('Add Resource'),
|
|
51
|
+
resources: [],
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Individual components composed manually
|
|
56
|
+
export const ComposedManually: Story = {
|
|
57
|
+
render: () => (
|
|
58
|
+
<ZoneContainer>
|
|
59
|
+
<ZoneHeader
|
|
60
|
+
name="Bowling"
|
|
61
|
+
status="active"
|
|
62
|
+
totalCapacity={2}
|
|
63
|
+
menuItems={zoneMenuItems}
|
|
64
|
+
/>
|
|
65
|
+
<ResourceRow
|
|
66
|
+
name="Table"
|
|
67
|
+
quantity={1}
|
|
68
|
+
capacity={1}
|
|
69
|
+
menuItems={resourceMenuItems}
|
|
70
|
+
onClick={() => alert('Edit Table')}
|
|
71
|
+
/>
|
|
72
|
+
<ResourceRow
|
|
73
|
+
name="Lane"
|
|
74
|
+
quantity={1}
|
|
75
|
+
capacity={1}
|
|
76
|
+
menuItems={resourceMenuItems}
|
|
77
|
+
onClick={() => alert('Edit Lane')}
|
|
78
|
+
/>
|
|
79
|
+
<AddResourceButton onClick={() => alert('Add Resource')} />
|
|
80
|
+
</ZoneContainer>
|
|
81
|
+
),
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Standalone ZoneHeader
|
|
85
|
+
export const StandaloneHeader: Story = {
|
|
86
|
+
render: () => (
|
|
87
|
+
<ZoneContainer>
|
|
88
|
+
<ZoneHeader
|
|
89
|
+
name="Main Floor"
|
|
90
|
+
status="active"
|
|
91
|
+
totalCapacity={50}
|
|
92
|
+
menuItems={zoneMenuItems}
|
|
93
|
+
/>
|
|
94
|
+
</ZoneContainer>
|
|
95
|
+
),
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Standalone ResourceRow
|
|
99
|
+
export const StandaloneResource: Story = {
|
|
100
|
+
render: () => (
|
|
101
|
+
<ZoneContainer>
|
|
102
|
+
<ResourceRow
|
|
103
|
+
name="Table"
|
|
104
|
+
quantity={10}
|
|
105
|
+
capacity={4}
|
|
106
|
+
menuItems={resourceMenuItems}
|
|
107
|
+
onClick={() => alert('Edit Table')}
|
|
108
|
+
/>
|
|
109
|
+
</ZoneContainer>
|
|
110
|
+
),
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Multiple zones
|
|
114
|
+
export const MultipleZones: Story = {
|
|
115
|
+
render: () => (
|
|
116
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
|
|
117
|
+
<ZoneCard
|
|
118
|
+
name="Bowling"
|
|
119
|
+
status="active"
|
|
120
|
+
totalCapacity={2}
|
|
121
|
+
menuItems={zoneMenuItems}
|
|
122
|
+
onAddResource={() => alert('Add Resource')}
|
|
123
|
+
resources={[
|
|
124
|
+
{ id: '1', name: 'Table', quantity: 1, capacity: 1, menuItems: resourceMenuItems },
|
|
125
|
+
{ id: '2', name: 'Lane', quantity: 1, capacity: 1, menuItems: resourceMenuItems },
|
|
126
|
+
]}
|
|
127
|
+
/>
|
|
128
|
+
<ZoneCard
|
|
129
|
+
name="VIP Lounge"
|
|
130
|
+
status="active"
|
|
131
|
+
totalCapacity={20}
|
|
132
|
+
menuItems={zoneMenuItems}
|
|
133
|
+
onAddResource={() => alert('Add Resource')}
|
|
134
|
+
resources={[
|
|
135
|
+
{ id: '3', name: 'Sofa', quantity: 4, capacity: 5, menuItems: resourceMenuItems },
|
|
136
|
+
]}
|
|
137
|
+
/>
|
|
138
|
+
</div>
|
|
139
|
+
),
|
|
140
|
+
}
|