@meistrari/tela-build 1.26.0 → 1.27.0
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/components/tela/menubar/menubar-item.vue +1 -1
- package/components/tela/menubar/menubar-trigger.vue +1 -1
- package/components/tela/sidebar/sidebar-content.vue +10 -0
- package/components/tela/sidebar/sidebar-footer.vue +5 -0
- package/components/tela/sidebar/sidebar-header.vue +5 -0
- package/components/tela/sidebar/sidebar-item.vue +48 -0
- package/components/tela/sidebar/sidebar-logo.vue +21 -0
- package/components/tela/sidebar/sidebar-user.vue +47 -0
- package/components/tela/sidebar/sidebar.mdx +175 -0
- package/components/tela/sidebar/sidebar.stories.ts +190 -0
- package/components/tela/sidebar/sidebar.vue +5 -0
- package/package.json +1 -1
- package/unocss.config.ts +11 -0
|
@@ -22,7 +22,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
|
22
22
|
<MenubarItem
|
|
23
23
|
v-bind="forwarded"
|
|
24
24
|
:class="cn(
|
|
25
|
-
'relative flex cursor-pointer select-none items-center rounded-xl px-3 py-1.5 text-body-14-medium font-460 outline-none focus:bg-
|
|
25
|
+
'relative flex cursor-pointer select-none items-center rounded-xl px-3 py-1.5 text-body-14-medium font-460 outline-none focus:bg-muted data-[disabled]:pointer-events-none data-[disabled]:opacity-40',
|
|
26
26
|
inset && 'pl-8',
|
|
27
27
|
props.class,
|
|
28
28
|
)"
|
|
@@ -17,7 +17,7 @@ const forwardedProps = useForwardProps(delegatedProps)
|
|
|
17
17
|
v-bind="forwardedProps"
|
|
18
18
|
:class="
|
|
19
19
|
cn(
|
|
20
|
-
'flex items-center gap-2 cursor-pointer select-none px-2 py-1.5 text-sm font-medium outline-none rounded-lg hover:bg-
|
|
20
|
+
'flex items-center gap-2 cursor-pointer select-none px-2 py-1.5 text-sm font-medium outline-none rounded-lg hover:bg-lowered data-[state=open]:bg-lowered',
|
|
21
21
|
props.class,
|
|
22
22
|
)
|
|
23
23
|
"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
flex flex-col h-full overflow-y-auto no-scrollbar
|
|
4
|
+
class="[mask-image:linear-gradient(to_bottom,transparent,black_20px,black_calc(100%_-_20px),transparent)]"
|
|
5
|
+
>
|
|
6
|
+
<nav flex flex-col items-center gap-14px h-full px-10px pt-12px mb-48px>
|
|
7
|
+
<slot />
|
|
8
|
+
</nav>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { NuxtLink } from '#components'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
icon: string
|
|
6
|
+
label: string
|
|
7
|
+
to?: string
|
|
8
|
+
onClick?: () => void
|
|
9
|
+
isActive: boolean
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
const iconName = computed(() => props.isActive ? `${props.icon}-fill` : props.icon)
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<component
|
|
17
|
+
:is="to ? NuxtLink : 'button'"
|
|
18
|
+
:to="to"
|
|
19
|
+
:type="!to ? 'button' : undefined"
|
|
20
|
+
class="group"
|
|
21
|
+
flex="~ col" items-center justify-center gap-2px outline-none
|
|
22
|
+
:data-active="isActive"
|
|
23
|
+
v-bind="!to && onClick ? { onClick } : {}"
|
|
24
|
+
>
|
|
25
|
+
<div relative size-40px flex items-center justify-center rounded-10px>
|
|
26
|
+
<TelaIcon
|
|
27
|
+
:name="iconName"
|
|
28
|
+
size="20px"
|
|
29
|
+
relative z-1
|
|
30
|
+
:color="isActive ? 'icon' : 'icon-tertiary duration-150 ease-out group-hover:icon group-focus-within:icon'"
|
|
31
|
+
/>
|
|
32
|
+
<div
|
|
33
|
+
:class="cn(
|
|
34
|
+
'absolute inset-0 size-full rounded-[14px] z-0 border-[0.5px] border-transparent',
|
|
35
|
+
isActive ? 'bg-neutral-200 group-focus-within:border-strong' : 'bg scale-10 opacity-0 duration-150 ease-out origin-center group-hover:border-strong group-hover:scale-100 group-hover:opacity-100 group-focus-within:border-strong group-focus-within:scale-100 group-focus-within:opacity-100',
|
|
36
|
+
)"
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
<p
|
|
40
|
+
:class="cn(
|
|
41
|
+
'text-[11px] leading-[12px] -tracking-0.2px',
|
|
42
|
+
isActive ? 'text-primary font-550' : 'font-460 text-tertiary duration-150 ease-out group-hover:text-primary group-focus-within:text-primary',
|
|
43
|
+
)"
|
|
44
|
+
>
|
|
45
|
+
{{ label }}
|
|
46
|
+
</p>
|
|
47
|
+
</component>
|
|
48
|
+
</template>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { NuxtLink } from '#components'
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
src?: string
|
|
6
|
+
alt: string
|
|
7
|
+
to?: string
|
|
8
|
+
}>()
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<component
|
|
13
|
+
:is="to ? NuxtLink : 'div'"
|
|
14
|
+
:to="to"
|
|
15
|
+
class="rounded-12px overflow-hidden outline-none focus-within:ring-0.5px focus-within:ring-border-strong"
|
|
16
|
+
>
|
|
17
|
+
<img v-if="src" :src="src" :alt="alt" w-40px h-40px object-cover>
|
|
18
|
+
<TelaInitials v-else-if="alt" size="md" :word="alt" />
|
|
19
|
+
<div v-else w-40px h-40px bg-black />
|
|
20
|
+
</component>
|
|
21
|
+
</template>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps<{
|
|
3
|
+
image?: string
|
|
4
|
+
name: string
|
|
5
|
+
email: string
|
|
6
|
+
actions: {
|
|
7
|
+
label: string
|
|
8
|
+
icon: string
|
|
9
|
+
color: 'positive' | 'caution' | 'negative'
|
|
10
|
+
onClick: () => void
|
|
11
|
+
}[]
|
|
12
|
+
}>()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<TelaDropdownMenuRoot>
|
|
17
|
+
<TelaDropdownMenuTrigger as-child>
|
|
18
|
+
<button
|
|
19
|
+
:class="cn('group', image ? 'ring-transparent focus-within:ring-border-strong' : 'ring-border-strong focus-within:ring-border-accent')"
|
|
20
|
+
rounded-full overflow-hidden ring-0.5px
|
|
21
|
+
>
|
|
22
|
+
<img v-if="image" :src="image" :alt="name" w-32px h-32px object-cover>
|
|
23
|
+
<div v-else w-32px h-32px bg />
|
|
24
|
+
</button>
|
|
25
|
+
</TelaDropdownMenuTrigger>
|
|
26
|
+
<TelaDropdownMenuContent align="start" side="top" class="min-w-200px!">
|
|
27
|
+
<div px-12px py-8px>
|
|
28
|
+
<h5 heading-h5-semibold text-primary mb-2px>
|
|
29
|
+
{{ name }}
|
|
30
|
+
</h5>
|
|
31
|
+
<p body-12-regular text-secondary>
|
|
32
|
+
{{ email }}
|
|
33
|
+
</p>
|
|
34
|
+
</div>
|
|
35
|
+
<TelaDropdownMenuSeparator />
|
|
36
|
+
<TelaDropdownMenuItem
|
|
37
|
+
v-for="action in actions"
|
|
38
|
+
:key="action.label"
|
|
39
|
+
:icon="action.icon"
|
|
40
|
+
:color="action.color"
|
|
41
|
+
@click="action.onClick"
|
|
42
|
+
>
|
|
43
|
+
{{ action.label }}
|
|
44
|
+
</TelaDropdownMenuItem>
|
|
45
|
+
</TelaDropdownMenuContent>
|
|
46
|
+
</TelaDropdownMenuRoot>
|
|
47
|
+
</template>
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as SidebarStories from './sidebar.stories.ts';
|
|
3
|
+
|
|
4
|
+
<Meta of={SidebarStories} />
|
|
5
|
+
|
|
6
|
+
# TelaSidebar
|
|
7
|
+
|
|
8
|
+
A composable sidebar navigation system built from focused sub-components. Fixed 80px wide and full-height, designed for icon-based navigation with labels.
|
|
9
|
+
|
|
10
|
+
## Examples
|
|
11
|
+
|
|
12
|
+
### Full Sidebar
|
|
13
|
+
|
|
14
|
+
```vue
|
|
15
|
+
<TelaSidebar>
|
|
16
|
+
<TelaSidebarHeader>
|
|
17
|
+
<TelaSidebarLogo src="/tela-logo-black.svg" alt="Tela Logo" />
|
|
18
|
+
</TelaSidebarHeader>
|
|
19
|
+
|
|
20
|
+
<TelaSidebarContent>
|
|
21
|
+
<TelaSidebarItem
|
|
22
|
+
v-for="item in items"
|
|
23
|
+
:key="item.label"
|
|
24
|
+
:icon="item.icon"
|
|
25
|
+
:label="item.label"
|
|
26
|
+
:to="item.path"
|
|
27
|
+
:is-active="isItemActive(item)"
|
|
28
|
+
:on-click="item.onClick"
|
|
29
|
+
/>
|
|
30
|
+
</TelaSidebarContent>
|
|
31
|
+
|
|
32
|
+
<TelaSidebarFooter>
|
|
33
|
+
<TelaSidebarItem
|
|
34
|
+
icon="i-ph-bell"
|
|
35
|
+
label="Activity"
|
|
36
|
+
:is-active="route.path === '/activity'"
|
|
37
|
+
/>
|
|
38
|
+
<TelaSidebarUser
|
|
39
|
+
:image="user.image"
|
|
40
|
+
:name="user.name"
|
|
41
|
+
:email="user.email"
|
|
42
|
+
:actions="[
|
|
43
|
+
{ label: 'Logout', icon: 'i-ph-sign-out', color: 'negative', onClick: handleLogout },
|
|
44
|
+
]"
|
|
45
|
+
/>
|
|
46
|
+
</TelaSidebarFooter>
|
|
47
|
+
</TelaSidebar>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
<Canvas of={SidebarStories.Default} />
|
|
51
|
+
|
|
52
|
+
### Activity Active
|
|
53
|
+
|
|
54
|
+
<Canvas of={SidebarStories.ActivityActive} />
|
|
55
|
+
|
|
56
|
+
### No Active Item
|
|
57
|
+
|
|
58
|
+
<Canvas of={SidebarStories.NoActiveItem} />
|
|
59
|
+
|
|
60
|
+
### Individual Item States
|
|
61
|
+
|
|
62
|
+
<Canvas of={SidebarStories.SingleItem} />
|
|
63
|
+
|
|
64
|
+
## Components
|
|
65
|
+
|
|
66
|
+
### `<TelaSidebar>`
|
|
67
|
+
|
|
68
|
+
Root wrapper. Renders as an `<aside>` with fixed 80px width, full height, and a right border. Place `TelaSidebarHeader`, `TelaSidebarContent`, and `TelaSidebarFooter` as direct children.
|
|
69
|
+
|
|
70
|
+
### `<TelaSidebarHeader>`
|
|
71
|
+
|
|
72
|
+
Top section of the sidebar. Stacks children vertically with 24px gap and vertical padding. Use for logos or workspace switchers.
|
|
73
|
+
|
|
74
|
+
### `<TelaSidebarLogo>`
|
|
75
|
+
|
|
76
|
+
Displays a logo or fallback inside the header. When `src` is provided, renders an image. When only `alt` is provided, falls back to `TelaInitials`. If neither is set, renders a placeholder div.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
interface TelaSidebarLogoProps {
|
|
80
|
+
src?: string // Image source URL or path — when provided, renders an <img>
|
|
81
|
+
alt: string // Accessible alt text — used as the word for TelaInitials fallback
|
|
82
|
+
to?: string // Optional link — wraps the content in a NuxtLink when provided
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `<TelaSidebarContent>`
|
|
87
|
+
|
|
88
|
+
Middle section that grows to fill available space. Scrollable with hidden scrollbar and a fade mask at the top and bottom edges for a smooth overflow effect. Place nav items directly as children — they stack vertically with 14px gap.
|
|
89
|
+
|
|
90
|
+
### `<TelaSidebarItem>`
|
|
91
|
+
|
|
92
|
+
An individual navigation item with an icon and label. Renders as a `NuxtLink` when `to` is provided, otherwise as a `<button>`.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface TelaSidebarItemProps {
|
|
96
|
+
icon: string // Iconify class (e.g. "i-ph-house")
|
|
97
|
+
label: string // Text label shown below the icon
|
|
98
|
+
isActive: boolean // Highlights the item as the current route
|
|
99
|
+
to?: string // Route path — renders as a link
|
|
100
|
+
onClick?: () => void // Click handler when not using `to`
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
<ArgTypes of={SidebarStories} />
|
|
105
|
+
|
|
106
|
+
### `<TelaSidebarFooter>`
|
|
107
|
+
|
|
108
|
+
Bottom section of the sidebar. Always contains `TelaSidebarUser` for account controls. Optionally add secondary `TelaSidebarItem` actions (e.g. activity, notifications) above it.
|
|
109
|
+
|
|
110
|
+
Default — user only:
|
|
111
|
+
|
|
112
|
+
```vue
|
|
113
|
+
<TelaSidebarFooter>
|
|
114
|
+
<TelaSidebarUser
|
|
115
|
+
:avatar-url="user.avatarUrl"
|
|
116
|
+
:username="user.name"
|
|
117
|
+
:email="user.email"
|
|
118
|
+
:options="[
|
|
119
|
+
{ label: 'Logout', icon: 'i-ph-sign-out', color: 'negative', onClick: handleLogout },
|
|
120
|
+
]"
|
|
121
|
+
/>
|
|
122
|
+
</TelaSidebarFooter>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
With secondary actions:
|
|
126
|
+
|
|
127
|
+
```vue
|
|
128
|
+
<TelaSidebarFooter>
|
|
129
|
+
<TelaSidebarItem
|
|
130
|
+
icon="i-ph-bell"
|
|
131
|
+
label="Activity"
|
|
132
|
+
:is-active="route.path === '/activity'"
|
|
133
|
+
to="/activity"
|
|
134
|
+
/>
|
|
135
|
+
<TelaSidebarUser
|
|
136
|
+
:avatar-url="user.avatarUrl"
|
|
137
|
+
:username="user.name"
|
|
138
|
+
:email="user.email"
|
|
139
|
+
:options="[
|
|
140
|
+
{ label: 'Logout', icon: 'i-ph-sign-out', color: 'negative', onClick: handleLogout },
|
|
141
|
+
]"
|
|
142
|
+
/>
|
|
143
|
+
</TelaSidebarFooter>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### `<TelaSidebarUser>`
|
|
147
|
+
|
|
148
|
+
User account button in the footer. Clicking opens a dropdown menu with the user's name, email, and configurable action items.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
interface TelaSidebarUserProps {
|
|
152
|
+
image?: string // Optional — falls back to a placeholder if not provided
|
|
153
|
+
name: string
|
|
154
|
+
email: string
|
|
155
|
+
actions: {
|
|
156
|
+
label: string
|
|
157
|
+
icon: string
|
|
158
|
+
color: 'positive' | 'caution' | 'negative'
|
|
159
|
+
onClick: () => void
|
|
160
|
+
}[]
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Example:
|
|
165
|
+
|
|
166
|
+
```vue
|
|
167
|
+
<TelaSidebarUser
|
|
168
|
+
image="https://example.com/avatar.jpg"
|
|
169
|
+
name="Jane Doe"
|
|
170
|
+
email="jane@example.com"
|
|
171
|
+
:actions="[
|
|
172
|
+
{ label: 'Logout', icon: 'i-ph-sign-out', color: 'negative', onClick: handleLogout },
|
|
173
|
+
]"
|
|
174
|
+
/>
|
|
175
|
+
```
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
import TelaSidebar from './sidebar.vue'
|
|
3
|
+
import TelaSidebarHeader from './sidebar-header.vue'
|
|
4
|
+
import TelaSidebarContent from './sidebar-content.vue'
|
|
5
|
+
import TelaSidebarLogo from './sidebar-logo.vue'
|
|
6
|
+
import TelaSidebarItem from './sidebar-item.vue'
|
|
7
|
+
import TelaSidebarFooter from './sidebar-footer.vue'
|
|
8
|
+
import TelaSidebarUser from './sidebar-user.vue'
|
|
9
|
+
|
|
10
|
+
const meta: Meta<typeof TelaSidebar> = {
|
|
11
|
+
title: 'Patterns/Sidebar',
|
|
12
|
+
component: TelaSidebar,
|
|
13
|
+
parameters: {
|
|
14
|
+
layout: 'fullscreen',
|
|
15
|
+
docs: {
|
|
16
|
+
description: {
|
|
17
|
+
component: 'A composable sidebar navigation system built from focused sub-components. Fixed 80px wide and full-height, designed for icon-based navigation with labels. Compose `TelaSidebarHeader`, `TelaSidebarContent`, and `TelaSidebarFooter` inside the root `TelaSidebar` to build the full layout.',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default meta
|
|
24
|
+
|
|
25
|
+
type Story = StoryObj<typeof TelaSidebar>
|
|
26
|
+
|
|
27
|
+
const navItems = [
|
|
28
|
+
{ icon: 'i-ph-house', label: 'Home', path: '/' },
|
|
29
|
+
{ icon: 'i-ph-graph', label: 'Workflows', path: '/workflows' },
|
|
30
|
+
{ icon: 'i-ph-database', label: 'Data', path: '/data' },
|
|
31
|
+
{ icon: 'i-ph-gear', label: 'Settings', path: '/settings' },
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
const userActions = [
|
|
35
|
+
{ label: 'Logout', icon: 'i-ph-sign-out', color: 'negative' as const, onClick: () => {} },
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
const components = {
|
|
39
|
+
TelaSidebar,
|
|
40
|
+
TelaSidebarHeader,
|
|
41
|
+
TelaSidebarLogo,
|
|
42
|
+
TelaSidebarContent,
|
|
43
|
+
TelaSidebarItem,
|
|
44
|
+
TelaSidebarFooter,
|
|
45
|
+
TelaSidebarUser,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const Default: Story = {
|
|
49
|
+
render: () => ({
|
|
50
|
+
components,
|
|
51
|
+
setup() {
|
|
52
|
+
const items = navItems
|
|
53
|
+
const activePath = '/workflows'
|
|
54
|
+
const isItemActive = (item: { path: string }) => activePath === item.path
|
|
55
|
+
return { items, isItemActive, userActions }
|
|
56
|
+
},
|
|
57
|
+
template: `
|
|
58
|
+
<TelaSidebar>
|
|
59
|
+
<TelaSidebarHeader>
|
|
60
|
+
<TelaSidebarLogo src="/tela-logo-black.svg" alt="Tela Logo" />
|
|
61
|
+
</TelaSidebarHeader>
|
|
62
|
+
|
|
63
|
+
<TelaSidebarContent>
|
|
64
|
+
<TelaSidebarItem
|
|
65
|
+
v-for="item in items"
|
|
66
|
+
:key="item.label"
|
|
67
|
+
:icon="item.icon"
|
|
68
|
+
:label="item.label"
|
|
69
|
+
:to="item.path"
|
|
70
|
+
:is-active="isItemActive(item)"
|
|
71
|
+
/>
|
|
72
|
+
<TelaSidebarItem
|
|
73
|
+
icon="i-ph-bell"
|
|
74
|
+
label="Activity"
|
|
75
|
+
:is-active="false"
|
|
76
|
+
/>
|
|
77
|
+
</TelaSidebarContent>
|
|
78
|
+
|
|
79
|
+
<TelaSidebarFooter>
|
|
80
|
+
<TelaSidebarUser
|
|
81
|
+
name="Username"
|
|
82
|
+
email="user@example.com"
|
|
83
|
+
:actions="userActions"
|
|
84
|
+
/>
|
|
85
|
+
</TelaSidebarFooter>
|
|
86
|
+
</TelaSidebar>
|
|
87
|
+
`,
|
|
88
|
+
}),
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const NoActiveItem: Story = {
|
|
92
|
+
render: () => ({
|
|
93
|
+
components,
|
|
94
|
+
setup() {
|
|
95
|
+
return { items: navItems, userActions }
|
|
96
|
+
},
|
|
97
|
+
template: `
|
|
98
|
+
<TelaSidebar>
|
|
99
|
+
<TelaSidebarHeader>
|
|
100
|
+
<TelaSidebarLogo src="/tela-logo-black.svg" alt="Tela Logo" />
|
|
101
|
+
</TelaSidebarHeader>
|
|
102
|
+
|
|
103
|
+
<TelaSidebarContent>
|
|
104
|
+
<TelaSidebarItem
|
|
105
|
+
v-for="item in items"
|
|
106
|
+
:key="item.label"
|
|
107
|
+
:icon="item.icon"
|
|
108
|
+
:label="item.label"
|
|
109
|
+
:to="item.path"
|
|
110
|
+
:is-active="false"
|
|
111
|
+
/>
|
|
112
|
+
<TelaSidebarItem
|
|
113
|
+
icon="i-ph-bell"
|
|
114
|
+
label="Activity"
|
|
115
|
+
:is-active="false"
|
|
116
|
+
/>
|
|
117
|
+
</TelaSidebarContent>
|
|
118
|
+
|
|
119
|
+
<TelaSidebarFooter>
|
|
120
|
+
<TelaSidebarUser
|
|
121
|
+
name="Username"
|
|
122
|
+
email="user@example.com"
|
|
123
|
+
:actions="userActions"
|
|
124
|
+
/>
|
|
125
|
+
</TelaSidebarFooter>
|
|
126
|
+
</TelaSidebar>
|
|
127
|
+
`,
|
|
128
|
+
}),
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const ActivityActive: Story = {
|
|
132
|
+
render: () => ({
|
|
133
|
+
components,
|
|
134
|
+
setup() {
|
|
135
|
+
return { items: navItems, userActions }
|
|
136
|
+
},
|
|
137
|
+
template: `
|
|
138
|
+
<TelaSidebar>
|
|
139
|
+
<TelaSidebarHeader>
|
|
140
|
+
<TelaSidebarLogo src="/tela-logo-black.svg" alt="Tela Logo" />
|
|
141
|
+
</TelaSidebarHeader>
|
|
142
|
+
|
|
143
|
+
<TelaSidebarContent>
|
|
144
|
+
<TelaSidebarItem
|
|
145
|
+
v-for="item in items"
|
|
146
|
+
:key="item.label"
|
|
147
|
+
:icon="item.icon"
|
|
148
|
+
:label="item.label"
|
|
149
|
+
:to="item.path"
|
|
150
|
+
:is-active="false"
|
|
151
|
+
/>
|
|
152
|
+
<TelaSidebarItem
|
|
153
|
+
icon="i-ph-bell"
|
|
154
|
+
label="Activity"
|
|
155
|
+
:is-active="true"
|
|
156
|
+
/>
|
|
157
|
+
</TelaSidebarContent>
|
|
158
|
+
|
|
159
|
+
<TelaSidebarFooter>
|
|
160
|
+
<TelaSidebarUser
|
|
161
|
+
name="Username"
|
|
162
|
+
email="user@example.com"
|
|
163
|
+
:actions="userActions"
|
|
164
|
+
/>
|
|
165
|
+
</TelaSidebarFooter>
|
|
166
|
+
</TelaSidebar>
|
|
167
|
+
`,
|
|
168
|
+
}),
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export const SingleItem: Story = {
|
|
172
|
+
parameters: {
|
|
173
|
+
layout: 'centered',
|
|
174
|
+
docs: {
|
|
175
|
+
description: {
|
|
176
|
+
story: 'Individual `TelaSidebarItem` in active and inactive states.',
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
render: () => ({
|
|
181
|
+
components: { TelaSidebarItem },
|
|
182
|
+
template: `
|
|
183
|
+
<div style="display: flex; gap: 24px; align-items: center;">
|
|
184
|
+
<TelaSidebarItem icon="i-ph-house" label="Home" :is-active="false" />
|
|
185
|
+
<TelaSidebarItem icon="i-ph-graph" label="Workflows" :is-active="true" />
|
|
186
|
+
<TelaSidebarItem icon="i-ph-bell" label="Activity" :is-active="false" />
|
|
187
|
+
</div>
|
|
188
|
+
`,
|
|
189
|
+
}),
|
|
190
|
+
}
|
package/package.json
CHANGED
package/unocss.config.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import transformerDirectives from '@unocss/transformer-directives'
|
|
2
2
|
import { defineConfig, toEscapedSelector } from 'unocss'
|
|
3
|
+
import type { Extractor } from 'unocss'
|
|
3
4
|
import { DT } from './utils/design-tokens'
|
|
4
5
|
|
|
6
|
+
/* Enables fill variants for Phosphor icons used as a dynamic suffix (e.g. `${icon}-fill`)
|
|
7
|
+
* in components, which UnoCSS can't detect through static scanning */
|
|
8
|
+
const phosphorFillExtractor: Extractor = {
|
|
9
|
+
name: 'phosphor-fill-icons',
|
|
10
|
+
extract: ({ code }) => new Set(
|
|
11
|
+
[...code.matchAll(/['"`](i-ph-[\w-]+)['"`]/g)].map(([, icon]) => `${icon}-fill`),
|
|
12
|
+
),
|
|
13
|
+
}
|
|
14
|
+
|
|
5
15
|
export default defineConfig({
|
|
16
|
+
extractors: [phosphorFillExtractor],
|
|
6
17
|
theme: {
|
|
7
18
|
...DT,
|
|
8
19
|
animation: {
|