diff --git a/packages/varlet-vue2-ui/src/card/Card.vue b/packages/varlet-vue2-ui/src/card/Card.vue new file mode 100644 index 0000000..1c54076 --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/Card.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/packages/varlet-vue2-ui/src/card/__tests__/__snapshots__/index.spec.js.snap b/packages/varlet-vue2-ui/src/card/__tests__/__snapshots__/index.spec.js.snap new file mode 100644 index 0000000..1d0c103 --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/__tests__/__snapshots__/index.spec.js.snap @@ -0,0 +1,61 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`test card example 1`] = ` +"
+
基本使用
+
+ +
风景
+ +
公园的树林也很美。在公园的小山上栽满了树木,梧桐树的叶子随着时间的流逝慢慢变黄,纷纷飘落;枫树的叶子却变红了,公园笼罩在片片红云中,也使秋天增添了一分热情。而柏树的叶子仍是那么青翠欲滴,令你陶醉极了。山上有一群孩子在快乐的嬉戏,不时传来阵阵欢笑声,瞧,他们玩得多起劲呀,给树林增添了活力。
+ +
+
显示副标题
+
+ +
风景
+
公园里的风景
+
公园的树林也很美。在公园的小山上栽满了树木,梧桐树的叶子随着时间的流逝慢慢变黄,纷纷飘落;枫树的叶子却变红了,公园笼罩在片片红云中,也使秋天增添了一分热情。而柏树的叶子仍是那么青翠欲滴,令你陶醉极了。山上有一群孩子在快乐的嬉戏,不时传来阵阵欢笑声,瞧,他们玩得多起劲呀,给树林增添了活力。
+ +
+
显示图片
+
+
风景
+
公园里的风景
+
公园的树林也很美。在公园的小山上栽满了树木,梧桐树的叶子随着时间的流逝慢慢变黄,纷纷飘落;枫树的叶子却变红了,公园笼罩在片片红云中,也使秋天增添了一分热情。而柏树的叶子仍是那么青翠欲滴,令你陶醉极了。山上有一群孩子在快乐的嬉戏,不时传来阵阵欢笑声,瞧,他们玩得多起劲呀,给树林增添了活力。
+ +
+
使用插槽
+
+
风景
+
公园里的风景
+
公园的树林也很美。在公园的小山上栽满了树木,梧桐树的叶子随着时间的流逝慢慢变黄,纷纷飘落;枫树的叶子却变红了,公园笼罩在片片红云中,也使秋天增添了一分热情。而柏树的叶子仍是那么青翠欲滴,令你陶醉极了。山上有一群孩子在快乐的嬉戏,不时传来阵阵欢笑声,瞧,他们玩得多起劲呀,给树林增添了活力。
+
+
+
水波效果
+
+ +
风景
+
公园里的风景
+
公园的树林也很美。在公园的小山上栽满了树木,梧桐树的叶子随着时间的流逝慢慢变黄,纷纷飘落;枫树的叶子却变红了,公园笼罩在片片红云中,也使秋天增添了一分热情。而柏树的叶子仍是那么青翠欲滴,令你陶醉极了。山上有一群孩子在快乐的嬉戏,不时传来阵阵欢笑声,瞧,他们玩得多起劲呀,给树林增添了活力。
+ +
+
" +`; + +exports[`test card props 1`] = ` +"
\\"This +
This is Card
+
This is subtitle
+
This is description
+
+
text
+
+
" +`; diff --git a/packages/varlet-vue2-ui/src/card/__tests__/index.spec.js b/packages/varlet-vue2-ui/src/card/__tests__/index.spec.js new file mode 100644 index 0000000..1fc3400 --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/__tests__/index.spec.js @@ -0,0 +1,66 @@ +import example from '../example' +import Vue from 'vue' +import Card from '..' +import VarCard from '../Card' +import { mount } from '@vue/test-utils' + +test('test card example', () => { + const wrapper = mount(example) + expect(wrapper.html()).toMatchSnapshot() + wrapper.destroy() +}) + +test('test card plugin', () => { + Vue.use(Card) + expect(Vue.component(Card.name)).toBeTruthy() +}) + +test('test card props', async () => { + const wrapper = mount(VarCard, { + propsData: { + title: 'This is Card', + description: 'This is description', + subtitle: 'This is subtitle', + src: 'https://varlet.gitee.io/varlet-ui/cat.jpg', + fit: 'cover', + height: '200px', + alt: 'This is an image', + elevation: '2', + ripple: true, + }, + scopedSlots: { + extra: '
text
', + }, + }) + + expect(wrapper.find('img').attributes('style')).toMatch('height: 200px') + expect(wrapper.find('img').attributes('style')).toMatch('object-fit: cover') + expect(wrapper.find('img').attributes('alt')).toMatch('This is an image') + expect(wrapper.find('img').attributes('src')).toMatch('https://varlet.gitee.io/varlet-ui/cat.jpg') + expect(wrapper.find('.var-card__title').text()).toBe('This is Card') + expect(wrapper.find('.var-card__subtitle').text()).toBe('This is subtitle') + expect(wrapper.find('.var-card__description').text()).toBe('This is description') + expect(wrapper.find('.var-card__footer').text()).toBe('text') + expect(wrapper.classes()).toContain('var-elevation--2') + expect(wrapper.html()).toMatchSnapshot() + wrapper.destroy() +}) + +test('test card onClick with null callback', () => { + const wrapper = mount(VarCard) + wrapper.trigger('click') + wrapper.destroy() +}) + +test('test card onClick', () => { + const onClick = jest.fn() + const wrapper = mount(VarCard, { + listeners: { + click: onClick, + }, + }) + + wrapper.trigger('click') + expect(onClick).toHaveBeenCalledTimes(1) + wrapper.destroy() +}) diff --git a/packages/varlet-vue2-ui/src/card/card.less b/packages/varlet-vue2-ui/src/card/card.less new file mode 100644 index 0000000..907e8bc --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/card.less @@ -0,0 +1,85 @@ +@card-padding: 0 0 15px 0; +@card-background: #fff; +@card-border-radius: 4px; +@card-image-width: 100%; +@card-image-height: 200px; +@card-title-color: #333; +@card-title-font-size: 20px; +@card-title-padding: 0 12px; +@card-title-margin: 15px 0 0 0; +@card-subtitle-color: rgba(0, 0, 0, 0.6); +@card-subtitle-font-size: 14px; +@card-subtitle-padding: 0 13px; +@card-subtitle-margin: 10px 0 0 0; +@card-description-color: rgba(0, 0, 0, 0.6); +@card-description-font-size: 14px; +@card-description-margin: 20px 0 0 0; +@card-description-padding: 0 13px; +@card-footer-padding: 0 12px; +@card-footer-margin: 30px 0 0px 0; +@card-line-height: 22px; + +:root { + --card-padding: @card-padding; + --card-background: @card-background; + --card-border-radius: @card-border-radius; + --card-image-width: @card-image-width; + --card-image-height: @card-image-height; + --card-title-color: @card-title-color; + --card-title-font-size: @card-title-font-size; + --card-title-padding: @card-title-padding; + --card-title-margin: @card-title-margin; + --card-subtitle-color: @card-subtitle-color; + --card-subtitle-font-size: @card-subtitle-font-size; + --card-subtitle-padding: @card-subtitle-padding; + --card-subtitle-margin: @card-subtitle-margin; + --card-description-color: @card-description-color; + --card-description-font-size: @card-description-font-size; + --card-description-margin: @card-description-margin; + --card-description-padding: @card-description-padding; + --card-footer-padding: @card-footer-padding; + --card-footer-margin: @card-footer-margin; + --card-line-height: @card-line-height; +} + +.var-card { + border-radius: var(--card-border-radius); + overflow: hidden; + padding: var(--card-padding); + line-height: var(--card-line-height); + background: var(--card-background); + transition: background-color 0.25s; + + &__image { + width: var(--card-image-width); + height: var(--card-image-height); + display: block; + } + + &__title { + font-size: var(--card-title-font-size); + padding: var(--card-title-padding); + margin: var(--card-title-margin); + color: var(--card-title-color); + } + + &__subtitle { + font-size: var(--card-subtitle-font-size); + color: var(--card-subtitle-color); + padding: var(--card-subtitle-padding); + margin: var(--card-subtitle-margin); + } + + &__description { + font-size: var(--card-description-font-size); + color: var(--card-description-color); + margin: var(--card-description-margin); + padding: var(--card-description-padding); + word-break: break-all; + } + + &__footer { + padding: var(--card-footer-padding); + margin: var(--card-footer-margin); + } +} diff --git a/packages/varlet-vue2-ui/src/card/docs/en-US.md b/packages/varlet-vue2-ui/src/card/docs/en-US.md new file mode 100644 index 0000000..76ab19e --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/docs/en-US.md @@ -0,0 +1,121 @@ +# Card + +### Intro + +```js +import Vue from 'vue' +import { Card } from '@varlet/ui' + +Vue.use(Card) +``` + +### Basic Use + +```html + +``` + +### Show Subtitle + +```html + +``` + +### Show Image + +```html + +``` + +### Use Slot + +```html + + + +``` + +### Ripple Effect + +```html + +``` + +## API + +### 属性 + +| Prop | Description | Type | Default | +| ------------- | --------------------------------------------------------------- | ------------------ | ------- | +| `title` | The title of Card | _string_ | `-` | +| `subtitle` | The subtitle of Card | _string_ | `-` | +| `description` | The description of Card | _string_ | `-` | +| `elevation` | The shadow level of Card | _string \| number_ | `2` | +| `src` | The src of Image | _string_ | `-` | +| `fit` | Fillmode, opitions `fill` `contain` `cover` `none` `scale-down` | _string_ | `cover` | +| `alt` | Alt text | _string_ | `-` | +| `height` | Heigth of Image | _string \| number_ | `-` | +| `ripple` | Whether to enable ripple | _boolean_ | `false` | + +### Slots + +| Slot | Description | Arguments | +| ------------- | --------------------- | --------- | +| `image` | Custom image | `-` | +| `title` | Custom title | `-` | +| `subtitle` | Custom subtitle | `-` | +| `description` | Custom description | `-` | +| `extra` | Custom bottom content | `-` | + +### Events + +| Events | Description | Arguments | +| ------- | -------------------------------- | -------------- | +| `click` | Triggered when the Card is click | `event: Event` | + +### Style Variables + +Here are the CSS variables used by the component, Styles can be customized using [StyleProvider](#/en-US/style-provider) + +| Variable | Default | +| ------------------------------ | -------------------- | +| `--card-background` | `#fff` | +| `--card-padding` | `0px 0 15px 0` | +| `--card-border-radius` | `4px` | +| `--card-image-width` | `100%` | +| `--card-image-height` | `200px` | +| `--card-title-color` | `#333` | +| `--card-title-font-size` | `20px` | +| `--card-title-padding` | `0 12px` | +| `--card-title-margin` | `15px 0 0 0` | +| `--card-subtitle-color` | `rgba(0, 0, 0, 0.6)` | +| `--card-subtitle-font-size` | `14px` | +| `--card-subtitle-padding` | `0 13px` | +| `--card-subtitle-margin` | `10px 0 0 0` | +| `--card-description-color` | `rgba(0, 0, 0, 0.6)` | +| `--card-description-font-size` | `14px` | +| `--card-description-margin` | `20px 0 0 0` | +| `--card-description-padding` | `0 13px` | +| `--card-footer-padding` | `0 12px` | +| `--card-footer-margin` | `30px 0 0px 0` | +| `--card-line-height` | `22px` | diff --git a/packages/varlet-vue2-ui/src/card/docs/zh-CN.md b/packages/varlet-vue2-ui/src/card/docs/zh-CN.md new file mode 100644 index 0000000..abe3dba --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/docs/zh-CN.md @@ -0,0 +1,126 @@ +# 卡片 + +### 引入 + +```js +import Vue from 'vue' +import { Card } from '@varlet/ui' + +Vue.use(Card) +``` + +### 基本使用 + +```html + +``` + +### 显示副标题 + +```html + +``` + +### 显示图片 + +```html + +``` + +### 使用插槽 + +```html + + + +``` + +### 水波效果 + +```html + +``` + +## API + +### 属性 + +| 参数 | 说明 | 类型 | 默认值 | +| ------------- | --------------------------------------------------------------- | ------------------ | ------- | +| `title` | 卡片标题 | _string_ | `-` | +| `subtitle` | 卡片副标题 | _string_ | `-` | +| `description` | 卡片描述 | _string_ | `-` | +| `elevation` | 卡片阴影程度等级 | _string \| number_ | `2` | +| `src` | 图片地址 | _string_ | `-` | +| `fit` | 填充模式,可选值为 `fill` `contain` `cover` `none` `scale-down` | _string_ | `cover` | +| `alt` | 替代文本 | _string_ | `-` | +| `height` | 图片高度 | _string \| number_ | `-` | +| `ripple` | 是否开启水波 | _boolean_ | `false` | + +### 插槽 + +| 插槽名 | 说明 | 参数 | +| ------------- | -------------- | ---- | +| `image` | 自定义图片 | `-` | +| `title` | 自定义标题 | `-` | +| `subtitle` | 自定义副标题 | `-` | +| `description` | 自定义描述 | `-` | +| `extra` | 自定义底部内容 | `-` | + +### 事件 + +| 事件名 | 说明 | 参数 | +| ------- | -------------- | -------------- | +| `click` | 点击卡片时触发 | `event: Event` | + +### 样式变量 + +以下为组件使用的 css 变量,可以使用 [StyleProvider 组件](#/zh-CN/style-provider)进行样式定制 + +| 变量名 | 默认值 | +| ------------------------------ | -------------------- | +| `--card-background` | `#fff` | +| `--card-padding` | `0px 0 15px 0` | +| `--card-border-radius` | `4px` | +| `--card-image-width` | `100%` | +| `--card-image-height` | `200px` | +| `--card-title-color` | `#333` | +| `--card-title-font-size` | `20px` | +| `--card-title-padding` | `0 12px` | +| `--card-title-margin` | `15px 0 0 0` | +| `--card-subtitle-color` | `rgba(0, 0, 0, 0.6)` | +| `--card-subtitle-font-size` | `14px` | +| `--card-subtitle-padding` | `0 13px` | +| `--card-subtitle-margin` | `10px 0 0 0` | +| `--card-description-color` | `rgba(0, 0, 0, 0.6)` | +| `--card-description-font-size` | `14px` | +| `--card-description-margin` | `20px 0 0 0` | +| `--card-description-padding` | `0 13px` | +| `--card-footer-padding` | `0 12px` | +| `--card-footer-margin` | `30px 0 0px 0` | +| `--card-line-height` | `22px` | diff --git a/packages/varlet-vue2-ui/src/card/example/index.vue b/packages/varlet-vue2-ui/src/card/example/index.vue new file mode 100644 index 0000000..211bb91 --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/example/index.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/packages/varlet-vue2-ui/src/card/example/locale/en-US.ts b/packages/varlet-vue2-ui/src/card/example/locale/en-US.ts new file mode 100644 index 0000000..977f561 --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/example/locale/en-US.ts @@ -0,0 +1,12 @@ +export default { + basicUsage: 'Basic Usage', + title: 'Little Prince', + showSubtitle: 'Show Subtitle', + subtitle: 'little prince from', + description: + 'It took me a long time to learn where he came from. The little prince, whoasked me so many questions, never seemed to hear the ones I asked him. Itwas from words dropped by chance that, little by little, everything wasrevealed to me.', + showImage: 'Show Image', + useSlot: 'Use Slot', + button: 'Use Button', + showRipple: 'Ripple Effect', +} diff --git a/packages/varlet-vue2-ui/src/card/example/locale/index.ts b/packages/varlet-vue2-ui/src/card/example/locale/index.ts new file mode 100644 index 0000000..d2e375e --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/example/locale/index.ts @@ -0,0 +1,23 @@ +// lib +import _zhCN from '../../../locale/zh-CN' +import _enCN from '../../../locale/en-US' +// mobile example doc +import zhCN from './zh-CN' +import enUS from './en-US' +import { useLocale, add as _add, use as _use } from '../../../locale' + +const { add, use: exampleUse, pack, packs, merge } = useLocale() + +const use = (lang: string) => { + _use(lang) + exampleUse(lang) +} + +export { add, pack, packs, merge, use } + +// lib +_add('zh-CN', _zhCN) +_add('en-US', _enCN) +// mobile example doc +add('zh-CN', zhCN as any) +add('en-US', enUS as any) diff --git a/packages/varlet-vue2-ui/src/card/example/locale/zh-CN.ts b/packages/varlet-vue2-ui/src/card/example/locale/zh-CN.ts new file mode 100644 index 0000000..6af5709 --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/example/locale/zh-CN.ts @@ -0,0 +1,12 @@ +export default { + basicUsage: '基本使用', + title: '风景', + showSubtitle: '显示副标题', + subtitle: '公园里的风景', + description: + '公园的树林也很美。在公园的小山上栽满了树木,梧桐树的叶子随着时间的流逝慢慢变黄,纷纷飘落;枫树的叶子却变红了,公园笼罩在片片红云中,也使秋天增添了一分热情。而柏树的叶子仍是那么青翠欲滴,令你陶醉极了。山上有一群孩子在快乐的嬉戏,不时传来阵阵欢笑声,瞧,他们玩得多起劲呀,给树林增添了活力。', + showImage: '显示图片', + useSlot: '使用插槽', + button: '添加按钮', + showRipple: '水波效果', +} diff --git a/packages/varlet-vue2-ui/src/card/index.ts b/packages/varlet-vue2-ui/src/card/index.ts new file mode 100644 index 0000000..8548d84 --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/index.ts @@ -0,0 +1,10 @@ +import type { VueConstructor } from 'vue' +import Card from './Card.vue' + +Card.install = function (app: VueConstructor) { + app.component(Card.name, Card) +} + +export const _CardComponent = Card + +export default Card diff --git a/packages/varlet-vue2-ui/src/card/props.ts b/packages/varlet-vue2-ui/src/card/props.ts new file mode 100644 index 0000000..3000d05 --- /dev/null +++ b/packages/varlet-vue2-ui/src/card/props.ts @@ -0,0 +1,41 @@ +import type { PropType } from 'vue' + +function fitValidator(fit: string) { + return ['fill', 'contain', 'cover', 'none', 'scale-down'].includes(fit) +} + +export const props = { + src: { + type: String, + }, + fit: { + type: String as PropType<'fill' | 'contain' | 'cover' | 'none' | 'scale-down'>, + validator: fitValidator, + default: 'cover', + }, + height: { + type: [String, Number], + }, + alt: { + type: String, + }, + title: { + type: String, + }, + subtitle: { + type: String, + }, + description: { + type: String, + }, + elevation: { + type: [Number, String], + }, + ripple: { + type: Boolean, + default: false, + }, + onClick: { + type: Function as PropType<(e: Event) => void>, + }, +} diff --git a/packages/varlet-vue2-ui/types/card.d.ts b/packages/varlet-vue2-ui/types/card.d.ts new file mode 100644 index 0000000..b944ee7 --- /dev/null +++ b/packages/varlet-vue2-ui/types/card.d.ts @@ -0,0 +1,20 @@ +import { VarComponent } from './varComponent' + +export interface CardProps { + src?: string; + fit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'; + height?: string | number; + alt?: string; + title?: string; + subtitle?: string; + description?: string; + elevation?: string | number; + ripple?: boolean; + onClick?: (e: Event) => void; +} + +export class Card extends VarComponent { + $props: CardProps +} + +export class _CardComponent extends Card {} diff --git a/packages/varlet-vue2-ui/types/global.d.ts b/packages/varlet-vue2-ui/types/global.d.ts index 4279dba..8912eec 100644 --- a/packages/varlet-vue2-ui/types/global.d.ts +++ b/packages/varlet-vue2-ui/types/global.d.ts @@ -2,6 +2,8 @@ declare module 'vue' { export interface GlobalComponents { VarButton: typeof import('@varlet-vue2/ui')['_ButtonComponent'] VarLazy: typeof import('@varlet-vue2/ui')['_LazyComponent'] + VarCell: typeof import('@varlet-vue2/ui')['_CellComponent'] + VarCard: typeof import('@varlet-vue2/ui')['_CardComponent'] VarLocale: typeof import('@varlet-vue2/ui')['_LocaleComponent'] VarSkeleton: typeof import('@varlet-vue2/ui')['_SkeletonComponent'] VarChip: typeof import('@varlet-vue2/ui')['_ChipComponent'] diff --git a/packages/varlet-vue2-ui/types/index.d.ts b/packages/varlet-vue2-ui/types/index.d.ts index 92c1d18..2541b3b 100644 --- a/packages/varlet-vue2-ui/types/index.d.ts +++ b/packages/varlet-vue2-ui/types/index.d.ts @@ -3,6 +3,8 @@ import type { VueConstructor } from 'vue' export const install: (app: VueConstructor) => void export * from './button' +export * from './card' +export * from './cell' export * from './locale' export * from './skeleton' export * from './cell'