Skip to content

Commit

Permalink
feat(action-list): add <ActionList> (#358) (#364)
Browse files Browse the repository at this point in the history
close #358
  • Loading branch information
kiaking committed Nov 1, 2023
1 parent c536e3d commit dd89f13
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 22 deletions.
1 change: 1 addition & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ function sidebar(): DefaultTheme.SidebarItem[] {
text: 'Components',
collapsed: false,
items: [
{ text: 'SActionList', link: '/components/action-list' },
{ text: 'SAvatar', link: '/components/avatar' },
{ text: 'SButton', link: '/components/button' },
{ text: 'SButtonGroup', link: '/components/button-group' },
Expand Down
106 changes: 106 additions & 0 deletions docs/components/action-list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<script setup lang="ts">
import IconActivity from '@iconify-icons/ph/activity-bold'
import IconEye from '@iconify-icons/ph/eye-bold'
import IconTrash from '@iconify-icons/ph/trash-bold'
import SActionList, { type ActionList } from 'sefirot/components/SActionList.vue'

const list: ActionList = [
{ leadIcon: IconActivity, text: 'Show activity' },
{ leadIcon: IconEye, text: 'Preview' },
{ leadIcon: IconTrash, text: 'Delete item' }
]
</script>

# SActionList

`<SAvatarList>` is a vertical list of interactive actions or options.

<Showcase
path="/components/SActionList.vue"
story="/stories-components-sactionlist-01-playground-story-vue"
>
<SActionList :list="list" />
</Showcase>
## Usage

`<SActionList>` takes a prop `:list` which is array of items to be listed as options.

```vue
<script setup lang="ts">
import IconActivity from '@iconify-icons/ph/activity-bold'
import IconEye from '@iconify-icons/ph/eye-bold'
import IconTrash from '@iconify-icons/ph/trash-bold'
import SActionList, { type ActionList } from '@globalbrain/sefirot/lib/components/SActionList.vue'
const list: ActionList = [
{ leadIcon: IconActivity, text: 'Show activity' },
{ leadIcon: IconEye, text: 'Preview' },
{ leadIcon: IconTrash, text: 'Delete item' }
]
</script>
<template>
<SActionList :list="list" />
</template>
```

## Props

### `:list`

The options to be listed.

```ts
import { type IconifyIcon } from '@iconify/vue/dist/offline'

interface Props {
list?: ActionList
}

type ActionList = ActionListItem[]

interface ActionListItem {
// The icon to be displayed on the left side of the text.
leadIcon?: IconifyIcon

// The text to be displayed.
text: string

// The link to be navigated to when the item is clicked. When this
// prop is set, the item is rendered via `<SLink>`.
link?: string

// The callback to be called when the item is clicked.
onClick?(): void
}
```

```vue-html
<SActionList :list="[...]" />
```

## Types

### `ActionList`

The type of the `:list` prop.

```ts
type ActionList = ActionListItem[]
```
### `ActionListItem`
The type of action list item. See `:list` for the details.
```ts
import { type IconifyIcon } from '@iconify/vue/dist/offline'

interface ActionListItem {
leadIcon?: IconifyIcon
text: string
link?: string
onClick?(): void
}
```
23 changes: 23 additions & 0 deletions lib/components/SActionList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import SActionListItem, { type ActionListItem } from './SActionListItem.vue'
export type ActionList = ActionListItem[]
export type { ActionListItem }
defineProps<{
list: ActionList
}>()
</script>

<template>
<div class="SActionList">
<SActionListItem
v-for="item, index in list"
:key="index"
:lead-icon="item.leadIcon"
:text="item.text"
:link="item.link"
:on-click="item.onClick"
/>
</div>
</template>
64 changes: 64 additions & 0 deletions lib/components/SActionListItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<script setup lang="ts">
import { type IconifyIcon } from '@iconify/vue/dist/offline'
import SIcon from './SIcon.vue'
import SLink from './SLink.vue'
export interface ActionListItem {
leadIcon?: IconifyIcon
text: string
link?: string
onClick?(): void
}
defineProps<ActionListItem>()
</script>

<template>
<component
:is="link ? SLink : 'button'"
class="SActionList"
:href="link"
@click="() => onClick?.()"
>
<span v-if="leadIcon" class="lead-icon">
<SIcon class="lead-icon-svg" :icon="leadIcon" />
</span>
<span class="text">{{ text }}</span>
</component>
</template>
<style scoped lang="postcss">
.SActionList {
display: flex;
gap: 8px;
border-radius: 6px;
padding: 4px 8px;
width: 100%;
text-align: left;
line-height: 24px;
font-size: 14px;
transition: background-color 0.25s;
&:hover {
background-color: var(--c-bg-mute-1);
}
&:active {
background-color: var(--c-bg-mute-2);
transition: background-color 0.1s;
}
}
.lead-icon {
display: flex;
align-items: center;
height: 24px;
flex-shrink: 0;
color: var(--c-text-2);
}
.lead-icon-svg {
width: 16px;
height: 16px;
}
</style>
54 changes: 32 additions & 22 deletions lib/styles/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@
--c-neutral-dark-dimm-2: rgba(255, 255, 255, 0.16);
--c-neutral-dark-dimm-2: rgba(255, 255, 255, 0.24);

--c-text-light-1: #1f1f1f;
--c-text-light-2: rgba(60, 60, 67, 0.72);
--c-text-light-3: rgba(60, 60, 67, 0.39);
--c-text-light-1: #1c2024;
--c-text-light-2: rgba(0, 7, 20, 0.62);
--c-text-light-3: rgba(0, 4, 26, 0.51);

--c-text-dark-1: rgba(235, 235, 245, 0.98);
--c-text-dark-2: rgba(235, 235, 245, 0.6);
--c-text-dark-3: rgba(235, 235, 245, 0.3);
--c-text-dark-1: #edeef0;
--c-text-dark-2: rgba(239, 245, 255, 0.69);
--c-text-dark-3: rgba(228, 238, 255, 0.49);
}

/**
Expand All @@ -88,6 +88,15 @@
--c-divider: var(--c-divider-light-1);
--c-divider-light: var(--c-divider-light-2);

/* DEPRECATED: Use `--c-bg-mute-X`. */
--c-mute: #f1f1f1;
--c-mute-light: #f9f9f9;
--c-mute-lighter: #ffffff;
--c-mute-dark: #e3e3e3;
--c-mute-darker: #d1d1d1;
--c-mute-dimm-1: #f1f1f1;
--c-mute-dimm-2: #e3e3e3;

/* DEPRECATED: Use `--c-bg-soft`. */
--c-soft: var(--c-white-soft);

Expand All @@ -96,6 +105,10 @@
--c-bg-elv-3: #ffffff;
--c-bg-soft: #f9f9f9;

--c-bg-mute-1: #ebebef;
--c-bg-mute-2: #e4e4e9;
--c-bg-mute-3: #dddde3;

--c-divider-1: var(--c-divider-light-1);
--c-divider-2: var(--c-divider-light-2);

Expand All @@ -121,14 +134,6 @@
--c-text-inverse-2: var(--c-text-dark-2);
--c-text-inverse-3: var(--c-text-dark-3);

--c-mute: #f1f1f1;
--c-mute-light: #f9f9f9;
--c-mute-lighter: #ffffff;
--c-mute-dark: #e3e3e3;
--c-mute-darker: #d1d1d1;
--c-mute-dimm-1: #f1f1f1;
--c-mute-dimm-2: #e3e3e3;

--c-info: #0969da;
--c-info-light: #218bff;
--c-info-lighter: #54aeff;
Expand Down Expand Up @@ -249,6 +254,15 @@
--c-divider: var(--c-divider-dark-1);
--c-divider-light: var(--c-divider-dark-2);

/* DEPRECATED: Use `--c-bg-mute-X`. */
--c-mute: #2c2c2e;
--c-mute-light: #3a3a3c;
--c-mute-lighter: #505053;
--c-mute-dark: #222226;
--c-mute-darker: #1c1c1e;
--c-mute-dimm-1: #222226;
--c-mute-dimm-2: #2c2c2e;

/* DEPRECATED: Use `--c-bg-soft`. */
--c-soft: #222226;

Expand All @@ -257,6 +271,10 @@
--c-bg-elv-3: #1c1c1e;
--c-bg-soft: #222226;

--c-bg-mute-1: #2e3035;
--c-bg-mute-2: #35373c;
--c-bg-mute-3: #3c3f44;

--c-divider-1: var(--c-divider-dark-1);
--c-divider-2: var(--c-divider-dark-2);

Expand All @@ -282,14 +300,6 @@
--c-text-inverse-2: var(--c-text-light-2);
--c-text-inverse-3: var(--c-text-light-3);

--c-mute: #2c2c2e;
--c-mute-light: #3a3a3c;
--c-mute-lighter: #505053;
--c-mute-dark: #222226;
--c-mute-darker: #1c1c1e;
--c-mute-dimm-1: #222226;
--c-mute-dimm-2: #2c2c2e;

--c-info: #1f6feb;
--c-info-light: #388bfd;
--c-info-lighter: #58a6ff;
Expand Down
23 changes: 23 additions & 0 deletions stories/components/SActionList.01_Playground.story.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import IconActivity from '@iconify-icons/ph/activity-bold'
import IconEye from '@iconify-icons/ph/eye-bold'
import IconTrash from '@iconify-icons/ph/trash-bold'
import SActionList, { type ActionList } from 'sefirot/components/SActionList.vue'
const title = 'Components / SActionList / 01. Playground'
const docs = '/components/action-list'
const list: ActionList = [
{ leadIcon: IconActivity, text: 'Show activity' },
{ leadIcon: IconEye, text: 'Preview' },
{ leadIcon: IconTrash, text: 'Delete item' }
]
</script>

<template>
<Story :title="title" source="Not available" auto-props-disabled>
<Board :title="title" :docs="docs">
<SActionList :list="list" />
</Board>
</Story>
</template>
31 changes: 31 additions & 0 deletions stories/components/SActionList.02_In_Card.story.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script setup lang="ts">
import IconActivity from '@iconify-icons/ph/activity-bold'
import IconEye from '@iconify-icons/ph/eye-bold'
import IconTrash from '@iconify-icons/ph/trash-bold'
import SActionList, { type ActionList } from 'sefirot/components/SActionList.vue'
import SCard from 'sefirot/components/SCard.vue'
import SCardBlock from 'sefirot/components/SCardBlock.vue'
const title = 'Components / SActionList / 02. In Card'
const docs = '/components/action-list'
const list: ActionList = [
{ leadIcon: IconActivity, text: 'Show activity' },
{ leadIcon: IconEye, text: 'Preview' },
{ leadIcon: IconTrash, text: 'Delete item' }
]
</script>

<template>
<Story :title="title" source="Not available" auto-props-disabled>
<Board :title="title" :docs="docs">
<SCard class="max-w-256">
<SCardBlock>
<div class="p-12">
<SActionList :list="list" />
</div>
</SCardBlock>
</SCard>
</Board>
</Story>
</template>
28 changes: 28 additions & 0 deletions stories/components/SActionList.03_In_Card_Without_Icons.story.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script setup lang="ts">
import SActionList, { type ActionList } from 'sefirot/components/SActionList.vue'
import SCard from 'sefirot/components/SCard.vue'
import SCardBlock from 'sefirot/components/SCardBlock.vue'
const title = 'Components / SActionList / 03. In Card Without Icons'
const docs = '/components/action-list'
const list: ActionList = [
{ text: 'Show activity' },
{ text: 'Preview' },
{ text: 'Delete item' }
]
</script>

<template>
<Story :title="title" source="Not available" auto-props-disabled>
<Board :title="title" :docs="docs">
<SCard class="max-w-256">
<SCardBlock>
<div class="p-12">
<SActionList :list="list" />
</div>
</SCardBlock>
</SCard>
</Board>
</Story>
</template>

0 comments on commit dd89f13

Please sign in to comment.