Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(card): add :mode to root and header components #325

Merged
merged 2 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 54 additions & 6 deletions docs/components/card.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,41 @@ import SCardHeaderTitle from '@globalbrain/sefirot/lib/components/SCardHeaderTit

Learn more about each child component's usage in the following sections.

## Root

The `<SCard>` is the root component of the card. All child components must be placed under this component.

```vue-html
<SCard>
<SCardHeader>...</SCardHeader>
<SCardBlock>...</SCardBlock>
<SCardFooter>...</SCardFooter>
</SCard>
```

### Root mode

You may define `:mode` to change the appearance of the card. Usually, this is most used when creating "dangerous" cards, such as a card that displays a warning message before deleting something.

```ts
interface Props {
mode?: 'neutral' | 'info' | 'success' | 'warning' | 'danger'
}
```

```vue-html
<SCard mode="danger">
...
</SCard>
```

## Header

Use `<SCardHeader>` to display header element.
Use `<SCardHeader>` with `<SCardHeaderTitle>` and `<SCardActions>` to construct the header.

### Header title

`<SCardHeaderTitle>` allows you to display the title text.
The `<SCardHeaderTitle>` allows you to display the title text in the header.

```vue-html
<SCard>
Expand All @@ -102,7 +132,25 @@ Use `<SCardHeader>` to display header element.
</SCard>
```

### Actions
You may also pass `:mode` to change the appearance of the title text. Combine this prop with `:mode` prop of `<SCard>` to emphasize the card's purpose.

```ts
interface Props {
mode?: 'neutral' | 'info' | 'success' | 'warning' | 'danger'
}
```

```vue-html
<SCard mode="danger">
<SCardHeader>
<SCardHeaderTitle mode="danger">
Header title
</SCardHeaderTitle>
</SCardHeader>
</SCard>
```

### Header actions

You may use `<SCardHeaderActions>` with nested `<SCardHeaderAction>` to add header actions. `<SCardHeaderAction>` accepts following props, and emits `@click` event when user clicks on the button.

Expand Down Expand Up @@ -182,7 +230,7 @@ Use `<SCardBlock>` to display generic block element. This component is usually u
</SCard>
```

### Spacing
### Block spacing

The `<SCardBlock>` component provides a convenient way to control the padding of the block using the `:space` prop. You can choose between two values: `compact` or `wide`.

Expand Down Expand Up @@ -217,7 +265,7 @@ Similar to `<SCardHeader>`, use `<SCardFooter>` to add the "footer" section of t
</SCard>
```

### Actions
### Footer actions

`<SCardFooterAction>` accepts following props. As same as `<SCardHeaderAction>`, it uses [`<SButton>`](./button) component internally. Refer to the documentation of `<SButton>` for how the props work.

Expand All @@ -240,7 +288,7 @@ export interface Tooltip {
}
```

### Spacing
### Footer spacing

Same as, `<SCardBlock>`, `<SCardFooter>` also comes with `:space` props that lets you control the padding of the block. You may pass either `compact` or `wide` as a value.

Expand Down
21 changes: 18 additions & 3 deletions lib/components/SCard.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
<script setup lang="ts">
import { computed } from 'vue'
import { provideCardState } from '../composables/Card'

export type Size = 'small' | 'medium' | 'large'
export type Mode = 'neutral' | 'info' | 'success' | 'warning' | 'danger'

defineProps<{
const props = defineProps<{
size?: Size
mode?: Mode
}>()

const { isCollapsed } = provideCardState()

const classes = computed(() => [
props.size,
props.mode ?? 'neutral',
{ collapsed: isCollapsed.value }
])
</script>

<template>
<div class="SCard" :class="[size, { collapsed: isCollapsed }]">
<div class="SCard" :class="classes">
<slot />
</div>
</template>
Expand All @@ -20,11 +29,17 @@ const { isCollapsed } = provideCardState()
.SCard {
display: grid;
gap: 1px;
border: 1px solid var(--c-divider-2);
border: 1px solid transparent;
border-radius: 6px;
background-color: var(--c-gutter);
}

.SCard.neutral { border-color: var(--c-divider-2); }
.SCard.info { border-color: var(--c-info-border); }
.SCard.success { border-color: var(--c-success-border); }
.SCard.warning { border-color: var(--c-warning-border); }
.SCard.danger { border-color: var(--c-danger-border); }

.SCard.collapsed {
height: 48px;
overflow: hidden;
Expand Down
16 changes: 15 additions & 1 deletion lib/components/SCardHeaderTitle.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<script setup lang="ts">
export type Mode = 'neutral' | 'info' | 'success' | 'warning' | 'danger'

defineProps<{
mode?: Mode
}>()
</script>

<template>
<p class="SCardHeaderTitle">
<p class="SCardHeaderTitle" :class="[mode ?? 'neutral']">
<slot />
</p>
</template>
Expand All @@ -12,4 +20,10 @@
font-size: 14px;
font-weight: 600;
}

.SCardHeaderTitle.neutral { color: var(--c-text-1); }
.SCardHeaderTitle.info { color: var(--c-info-text); }
.SCardHeaderTitle.success { color: var(--c-success-text); }
.SCardHeaderTitle.warning { color: var(--c-warning-text); }
.SCardHeaderTitle.danger { color: var(--c-danger-text); }
</style>
88 changes: 61 additions & 27 deletions stories/components/SCard.01_Playground.story.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,71 @@ import SCardHeaderTitle from 'sefirot/components/SCardHeaderTitle.vue'

const title = 'Components / SCard / 01. Playground'
const docs = '/components/card'

function state() {
return {
cardMode: 'neutral',
titleMode: 'neutral'
}
}
</script>

<template>
<Story :title="title" source="Not available" auto-props-disabled>
<Board :title="title" :docs="docs">
<div class="max-w-512">
<SCard>
<SCardHeader>
<SCardHeaderTitle>Header title</SCardHeaderTitle>
<SCardHeaderActions>
<SCardHeaderActionClose />
</SCardHeaderActions>
</SCardHeader>
<Story :title="title" :init-state="state" source="Not available" auto-props-disabled>
<template #controls="{ state }">
<HstSelect
title="Card mode"
:options="{
neutral: 'neutral',
info: 'info',
success: 'success',
warning: 'warning',
danger: 'danger'
}"
v-model="state.cardMode"
/>
<HstSelect
title="Title mode"
:options="{
neutral: 'neutral',
info: 'info',
success: 'success',
warning: 'warning',
danger: 'danger'
}"
v-model="state.titleMode"
/>
</template>

<template #default="{ state }">
<Board :title="title" :docs="docs">
<div class="max-w-512">
<SCard :mode="state.cardMode">
<SCardHeader>
<SCardHeaderTitle :mode="state.titleMode">Header title</SCardHeaderTitle>
<SCardHeaderActions>
<SCardHeaderActionClose />
</SCardHeaderActions>
</SCardHeader>

<SCardBlock space="compact">
<p class="text-14">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</SCardBlock>
<SCardBlock space="compact">
<p class="text-14">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</SCardBlock>

<SCardFooter>
<SCardFooterActions>
<SCardFooterAction mode="mute" label="Cancel" />
<SCardFooterAction mode="info" label="Submit" />
</SCardFooterActions>
</SCardFooter>
</SCard>
</div>
</Board>
<SCardFooter>
<SCardFooterActions>
<SCardFooterAction mode="mute" label="Cancel" />
<SCardFooterAction mode="info" label="Submit" />
</SCardFooterActions>
</SCardFooter>
</SCard>
</div>
</Board>
</template>
</Story>
</template>
100 changes: 67 additions & 33 deletions stories/components/SCard.02_Within_Modal.story.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,75 @@ const title = 'Components / SCard / 02. Within Modal'
const docs = '/components/card'

const open = ref(false)

function state() {
return {
cardMode: 'neutral',
titleMode: 'neutral'
}
}
</script>

<template>
<Story :title="title" source="Not available" auto-props-disabled>
<div id="sefirot-modals" />

<Board :title="title" :docs="docs">
<SButton mode="info" label="Open dialog" @click="open = true" />

<SModal :open="open" @close="open = false">
<SCard size="small">
<SCardHeader>
<SCardHeaderTitle>Header title</SCardHeaderTitle>
<SCardHeaderActions>
<SCardHeaderActionClose @click="open = false" />
</SCardHeaderActions>
</SCardHeader>

<SCardBlock space="compact">
<p class="text-14">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</SCardBlock>

<SCardFooter>
<SCardFooterActions>
<SCardFooterAction mode="mute" label="Cancel" @click="open = false" />
<SCardFooterAction mode="info" label="Submit" @click="open = false" />
</SCardFooterActions>
</SCardFooter>
</SCard>
</SModal>
</Board>
<Story :title="title" :init-state="state" source="Not available" auto-props-disabled>
<template #controls="{ state }">
<HstSelect
title="Card mode"
:options="{
neutral: 'neutral',
info: 'info',
success: 'success',
warning: 'warning',
danger: 'danger'
}"
v-model="state.cardMode"
/>
<HstSelect
title="Title mode"
:options="{
neutral: 'neutral',
info: 'info',
success: 'success',
warning: 'warning',
danger: 'danger'
}"
v-model="state.titleMode"
/>
</template>

<template #default="{ state }">
<div id="sefirot-modals" />

<Board :title="title" :docs="docs">
<SButton mode="info" label="Open dialog" @click="open = true" />

<SModal :open="open" @close="open = false">
<SCard size="small" :mode="state.cardMode">
<SCardHeader>
<SCardHeaderTitle :mode="state.titleMode">Header title</SCardHeaderTitle>
<SCardHeaderActions>
<SCardHeaderActionClose @click="open = false" />
</SCardHeaderActions>
</SCardHeader>

<SCardBlock space="compact">
<p class="text-14">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</SCardBlock>

<SCardFooter>
<SCardFooterActions>
<SCardFooterAction mode="mute" label="Cancel" @click="open = false" />
<SCardFooterAction mode="info" label="Submit" @click="open = false" />
</SCardFooterActions>
</SCardFooter>
</SCard>
</SModal>
</Board>
</template>
</Story>
</template>
Loading