Skip to content
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
3 changes: 3 additions & 0 deletions packages/ccui/ui/shared/hooks/use-namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export interface UseNamespace {
e: (el: string) => string
m: (mo: string) => string
em: (el: string, mo: string) => string
is: (name: string) => string
}

function createBem(
Expand Down Expand Up @@ -35,10 +36,12 @@ export function useNamespace(block: string, needDot = false): UseNamespace {
modifier ? createBem(namespace, '', modifier) : ''
const em = (element: string, modifier: string) =>
element && modifier ? createBem(namespace, element, modifier) : ''
const is = (name: string) => `is-${name}`
return {
b,
e,
m,
em,
is,
}
}
19 changes: 19 additions & 0 deletions packages/ccui/ui/timeline/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { App } from 'vue'
import Timeline from './src/timeline'
import TimelineItem from './src/timeline-item'

Timeline.install = function (app: App) {
app.component(Timeline.name!, Timeline)
app.component(TimelineItem.name!, TimelineItem)
}

export { Timeline, TimelineItem }

export default {
title: 'Timeline 时间线',
category: '数据展示',
status: '100%',
install(app: App) {
Timeline.install(app)
},
}
103 changes: 103 additions & 0 deletions packages/ccui/ui/timeline/src/timeline-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import type { TimelineItemProps } from './timeline-types'
import { computed, defineComponent, h } from 'vue'
import { useNamespace } from '../../shared/hooks/use-namespace'
import { timelineItemProps } from './timeline-types'

export default defineComponent({
name: 'CTimelineItem',
props: timelineItemProps,
emits: [],
setup(props: TimelineItemProps, { slots }) {
const ns = useNamespace('timeline-item')

// 计算节点的样式类名
const nodeClasses = computed(() => {
return [
ns.e('node'),
ns.em('node', props.size),
props.type && ns.em('node', props.type),
props.hollow && ns.is('hollow'),
].filter(Boolean)
})

// 计算时间戳的样式类名
const timestampClasses = computed(() => {
return [
ns.e('timestamp'),
ns.is(props.placement),
]
})

// 渲染图标
const renderIcon = () => {
if (props.icon) {
if (typeof props.icon === 'string') {
return <i class={[props.icon, ns.e('icon')]}></i>
}
else {
// 如果是组件,使用 h 函数渲染
return h(props.icon, { class: ns.e('icon') })
}
}
return null
}

// 渲染节点
const renderNode = () => {
if (slots.dot) {
return (
<div class={ns.e('dot')}>
{slots.dot()}
</div>
)
}

return (
<div
class={nodeClasses.value}
style={props.color ? { backgroundColor: props.color, borderColor: props.color } : {}}
>
{renderIcon()}
</div>
)
}

// 渲染时间戳
const renderTimestamp = () => {
if (props.hideTimestamp)
return null

return (
<div class={timestampClasses.value}>
{props.timestamp}
</div>
)
}

return () => {
return (
<li class={[ns.b(), props.center && ns.e('center')]}>
{/* 连接线 */}
<div class={ns.e('tail')}></div>

{/* 节点 */}
{renderNode()}

{/* 内容区域 */}
<div class={ns.e('wrapper')}>
{/* 顶部时间戳 */}
{props.placement === 'top' && renderTimestamp()}

{/* 内容 */}
<div class={ns.e('content')}>
{slots.default && slots.default()}
</div>

{/* 底部时间戳 */}
{props.placement === 'bottom' && renderTimestamp()}
</div>
</li>
)
}
},
})
81 changes: 81 additions & 0 deletions packages/ccui/ui/timeline/src/timeline-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { Component, ExtractPropTypes, PropType } from 'vue'

// Timeline 主组件的 props
export const timelineProps = {
// 暂时没有特殊的 props,主要通过插槽传递 TimelineItem
} as const

export type TimelineProps = ExtractPropTypes<typeof timelineProps>

export type TimelineItemType = 'primary' | 'success' | 'warning' | 'danger' | 'info' | ''

// TimelineItem 组件的 props
export const timelineItemProps = {
/**
* 时间戳内容
*/
timestamp: {
type: String,
default: '',
},
/**
* 是否隐藏时间戳
*/
hideTimestamp: {
type: Boolean,
default: false,
},
/**
* 是否垂直居中
*/
center: {
type: Boolean,
default: false,
},
/**
* 时间戳位置
*/
placement: {
type: String as PropType<'top' | 'bottom'>,
default: 'bottom',
validator: (value: string) => ['top', 'bottom'].includes(value),
},
/**
* 节点类型
*/
type: {
type: String as PropType<TimelineItemType>,
default: '',
validator: (value: string) => ['primary', 'success', 'warning', 'danger', 'info', ''].includes(value),
},
/**
* 节点颜色
*/
color: {
type: String,
default: '',
},
/**
* 节点尺寸
*/
size: {
type: String as PropType<'normal' | 'large'>,
default: 'normal',
validator: (value: string) => ['normal', 'large'].includes(value),
},
/**
* 自定义图标
*/
icon: {
type: [String, Object] as PropType<string | Component>,
},
/**
* 是否空心点
*/
hollow: {
type: Boolean,
default: false,
},
} as const

export type TimelineItemProps = ExtractPropTypes<typeof timelineItemProps>
Loading