Skip to content

Commit

Permalink
Merge pull request #29 from qianmoQ/feature-components
Browse files Browse the repository at this point in the history
Support timeline
  • Loading branch information
qianmoQ authored Jul 13, 2024
2 parents 616cd3a + 6bf11db commit 39a1b6c
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/data/Navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ const createNavigation = (): void => {
const button = createNavigationItem('common.common.button', undefined, '/components/button', undefined, NavigationPosition.LEFT_TOP)
const card = createNavigationItem('common.common.card', undefined, '/components/card', undefined, NavigationPosition.LEFT_TOP)
const tree = createNavigationItem('common.common.tree', undefined, '/components/tree', undefined, NavigationPosition.LEFT_TOP)
const componentArray = [button, card, tree]
const timeline = createNavigationItem('common.common.timeline', undefined, '/components/timeline', undefined, NavigationPosition.LEFT_TOP)
const componentArray = [button, card, tree, timeline]
const components = createNavigationItem('common.common.component', componentArray.length.toString(), '/components', Command, NavigationPosition.LEFT_TOP, componentArray)
NavigationService.addNavigation(components)

Expand Down
1 change: 1 addition & 0 deletions src/i18n/langs/en/Common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default {
footerModern: 'Footer Modern',
navbar: 'Navbar',
tree: 'Tree',
timeline: 'Timeline',
},
tip: {
signInInfo: 'Enter your information to sign in to your account.',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/langs/zhCn/Common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default {
footerModern: '现代页脚',
navbar: '导航栏',
tree: '树',
timeline: '时间线',
},
tip: {
signInInfo: '输入您的信息以登录您的帐户。',
Expand Down
5 changes: 5 additions & 0 deletions src/router/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ const createComponentRouter = (router: Router): void => {
name: 'tree',
path: 'tree',
component: () => import('@/views/pages/components/TreeHome.vue')
},
{
name: 'timeline',
path: 'timeline',
component: () => import('@/views/pages/components/TimelineHome.vue')
}
]
})
Expand Down
10 changes: 10 additions & 0 deletions src/views/components/timeline/Timeline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface Timeline
{
id?: number | string
title?: string
time?: string
tip?: string
description?: string
type?: 'opened' | 'commented' | 'closed'
children?: Timeline[]
}
39 changes: 39 additions & 0 deletions src/views/components/timeline/default/DefaultTimeline.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<div v-for="item in items">
<div class="ps-2 my-2 first:mt-0">
<h3 class="text-xs font-medium uppercase text-gray-500 dark:text-neutral-400">{{ item.title }}</h3>
</div>
<div v-for="child in item.children" class="flex gap-x-3">
<div
class="relative last:after:hidden after:absolute after:top-7 after:bottom-0 after:start-3.5 after:w-px after:-translate-x-[0.5px] after:bg-gray-200 dark:after:bg-neutral-700">
<div class="relative z-10 size-7 flex justify-center items-center">
<div class="size-2 rounded-full bg-gray-400 dark:bg-neutral-600"></div>
</div>
</div>
<slot v-if="$slots.item" name="item" :item="child"/>
<div v-else class="grow pt-0.5 pb-8">
<h3 class="flex gap-x-1.5 font-semibold text-gray-800 dark:text-white">{{ child.title }}</h3>
<p class="mt-1 text-sm text-gray-600 dark:text-neutral-400">{{ child.description }}</p>
<button type="button"
class="mt-1 -ms-1 p-1 inline-flex items-center gap-x-2 text-xs rounded-lg border border-transparent text-gray-500 hover:bg-gray-100 disabled:opacity-50 disabled:pointer-events-none dark:text-neutral-400 dark:hover:bg-neutral-700">
{{ child.time }}
</button>
</div>
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { Timeline } from '@/views/components/timeline/Timeline.ts'
export default defineComponent({
name: 'DefaultTimeline',
props: {
items: {
type: Array<Timeline>,
required: true
}
}
})
</script>
50 changes: 50 additions & 0 deletions src/views/components/timeline/discussion/DiscussionTimeline.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<template>
<div
class="space-y-8 relative before:absolute before:inset-0 before:ml-5 before:-translate-x-px md:before:ml-[8.75rem] md:before:translate-x-0 before:h-full before:w-0.5 before:bg-gradient-to-b before:from-transparent before:via-slate-300 before:to-transparent">
<div v-for="item in items" class="relative">
<div class="md:flex items-center md:space-x-4 mb-3">
<div class="flex items-center space-x-4 md:space-x-2 md:space-x-reverse">
<div v-if="item.type === 'opened'" class="flex items-center justify-center w-10 h-10 rounded-full bg-white shadow md:order-1">
<svg class="fill-emerald-500" xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<path d="M8 0a8 8 0 1 0 8 8 8.009 8.009 0 0 0-8-8Zm0 12a4 4 0 1 1 0-8 4 4 0 0 1 0 8Z"/>
</svg>
</div>
<div v-else-if="item.type === 'commented'" class="flex items-center justify-center w-10 h-10 rounded-full bg-white shadow md:order-1">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<path class="fill-slate-300"
d="M14.853 6.861C14.124 10.348 10.66 13 6.5 13c-.102 0-.201-.016-.302-.019C7.233 13.618 8.557 14 10 14c.51 0 1.003-.053 1.476-.143L14.2 15.9a.499.499 0 0 0 .8-.4v-3.515c.631-.712 1-1.566 1-2.485 0-.987-.429-1.897-1.147-2.639Z"/>
<path class="fill-slate-500"
d="M6.5 0C2.91 0 0 2.462 0 5.5c0 1.075.37 2.074 1 2.922V11.5a.5.5 0 0 0 .8.4l1.915-1.436c.845.34 1.787.536 2.785.536 3.59 0 6.5-2.462 6.5-5.5S10.09 0 6.5 0Z"/>
</svg>
</div>
<div v-else-if="item.type === 'closed'" class="flex items-center justify-center w-10 h-10 rounded-full bg-white shadow md:order-1">
<svg class="fill-red-500" xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<path d="M8 0a8 8 0 1 0 8 8 8.009 8.009 0 0 0-8-8Zm0 12a4 4 0 1 1 0-8 4 4 0 0 1 0 8Z"/>
</svg>
</div>
<div v-else class="flex items-center justify-center w-10 h-10 rounded-full bg-white shadow md:order-1"/>
<time class="font-caveat font-medium text-xl text-indigo-500 md:w-28">{{ item.time }}</time>
</div>
<div class="text-slate-500 ml-14"><span class="text-slate-900 font-bold">{{ item.title }}</span> {{ item.type }}</div>
</div>
<div class="bg-white p-4 rounded border border-slate-200 text-slate-500 shadow ml-14 md:ml-44">
{{ item.description }}
</div>
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { Timeline } from '@/views/components/timeline/Timeline.ts'
export default defineComponent({
name: 'DiscussionTimeline',
props: {
items: {
type: Array<Timeline>,
required: true
}
}
})
</script>
32 changes: 32 additions & 0 deletions src/views/components/timeline/milestone/MilestoneTimeline.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<template>
<div v-for="item in items" class="relative pl-8 sm:pl-32 py-6 group">
<slot v-if="$slots.item" name="item" :item="item"/>
<div v-else>
<div class="font-medium text-2xl text-indigo-500 mb-1 sm:mb-0">{{ item.title }}</div>
<div
class="flex flex-col sm:flex-row items-start mb-1 group-last:before:hidden before:absolute before:left-2 sm:before:left-0 before:h-full before:px-px before:bg-slate-300 sm:before:ml-[6.5rem] before:self-start before:-translate-x-1/2 before:translate-y-3 after:absolute after:left-2 sm:after:left-0 after:w-2 after:h-2 after:bg-indigo-600 after:border-4 after:box-content after:border-slate-50 after:rounded-full sm:after:ml-[6.5rem] after:-translate-x-1/2 after:translate-y-1.5">
<span
class="sm:absolute left-0 translate-y-0.5 inline-flex items-center justify-center text-xs font-semibold uppercase w-20 h-6 mb-3 sm:mb-0 text-emerald-600 bg-emerald-100 rounded-full">
{{ item.time }}
</span>
<div class="text-xl font-bold text-slate-900">{{ item.tip }}</div>
</div>
<div class="text-slate-500">{{ item.description }}</div>
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { Timeline } from '@/views/components/timeline/Timeline.ts'
export default defineComponent({
name: 'MilestoneTimeline',
props: {
items: {
type: Array<Timeline>,
required: true
}
}
})
</script>
38 changes: 38 additions & 0 deletions src/views/components/timeline/progress/ProgressTimeline.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<template>
<div
class="space-y-8 relative before:absolute before:inset-0 before:ml-5 before:-translate-x-px md:before:mx-auto md:before:translate-x-0 before:h-full before:w-0.5 before:bg-gradient-to-b before:from-transparent before:via-slate-300 before:to-transparent">
<div v-for="item in items" class="relative flex items-center justify-between md:justify-normal md:odd:flex-row-reverse group is-active">
<slot v-if="$slots.item" name="item" :item="item"/>
<template v-else>
<div
class="flex items-center justify-center w-10 h-10 rounded-full border border-white bg-slate-300 group-[.is-active]:bg-emerald-500 text-slate-500 group-[.is-active]:text-emerald-50 shadow shrink-0 md:order-1 md:group-odd:-translate-x-1/2 md:group-even:translate-x-1/2">
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" width="12" height="10">
<path fill-rule="nonzero" d="M10.422 1.257 4.655 7.025 2.553 4.923A.916.916 0 0 0 1.257 6.22l2.75 2.75a.916.916 0 0 0 1.296 0l6.415-6.416a.916.916 0 0 0-1.296-1.296Z"/>
</svg>
</div>
<div class="w-[calc(100%-4rem)] md:w-[calc(50%-2.5rem)] bg-white p-4 rounded border border-slate-200 shadow">
<div class="flex items-center justify-between space-x-2 mb-1">
<div class="font-bold text-slate-900">{{ item.title }}</div>
<time class="font-caveat font-medium text-indigo-500">{{ item.time }}</time>
</div>
<div class="text-slate-500">{{ item.description }}</div>
</div>
</template>
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { Timeline } from '@/views/components/timeline/Timeline.ts'
export default defineComponent({
name: 'ProgressTimeline',
props: {
items: {
type: Array<Timeline>,
required: true
}
}
})
</script>
136 changes: 136 additions & 0 deletions src/views/pages/components/TimelineHome.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<template>
<div class="flex w-full flex-col gap-4 md:gap-8 md:p-8 lg:grid lg:grid-cols-2">
<ICard body-class="pt-3">
<template #title>Default</template>
<DefaultTimeline :items="items"/>
</ICard>
<ICard body-class="pt-3">
<template #title>Custom Slot</template>
<DefaultTimeline :items="items">
<template #item="{ item }">
<div class="grow pt-0.5 pb-8">
<h3 class="flex gap-x-1.5 font-semibold text-gray-800 dark:text-white">
<svg class="flex-shrink-0 size-4 mt-1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" x2="8" y1="13" y2="13"></line>
<line x1="16" x2="8" y1="17" y2="17"></line>
<line x1="10" x2="8" y1="9" y2="9"></line>
</svg>
{{ item.title }}
</h3>
<p class="mt-1 text-sm text-gray-600 dark:text-neutral-400">
{{ item.description }}
</p>
<button type="button"
class="mt-1 -ms-1 p-1 inline-flex items-center gap-x-2 text-xs rounded-lg border border-transparent text-gray-500 hover:bg-gray-100 disabled:opacity-50 disabled:pointer-events-none dark:text-neutral-400 dark:hover:bg-neutral-700">
<img class="flex-shrink-0 size-4 rounded-full" src="https://avatars.githubusercontent.com/u/135088160?s=200&v=4" alt="Image Description">
{{ item.time }}
</button>
</div>
</template>
</DefaultTimeline>
</ICard>
<ICard body-class="pt-3">
<template #title>Milestone</template>
<MilestoneTimeline :items="items[0].children as any[]"/>
</ICard>
<ICard body-class="pt-3">
<template #title>Milestone Slot</template>
<MilestoneTimeline :items="items[0].children as any[]">
<template #item="{ item }">
<div
class="flex flex-col sm:flex-row items-start mb-1 group-last:before:hidden before:absolute before:left-2 sm:before:left-0 before:h-full before:px-px before:bg-slate-300 sm:before:ml-[6.5rem] before:self-start before:-translate-x-1/2 before:translate-y-3 after:absolute after:left-2 sm:after:left-0 after:w-2 after:h-2 after:bg-indigo-600 after:border-4 after:box-content after:border-slate-50 after:rounded-full sm:after:ml-[6.5rem] after:-translate-x-1/2 after:translate-y-1.5">
<div class="text-xl font-bold text-slate-900">{{ item.title }}</div>
</div>
</template>
</MilestoneTimeline>
</ICard>
<ICard body-class="pt-3">
<template #title>Progress</template>
<ProgressTimeline :items="items[0].children as any[]"/>
</ICard>
<ICard body-class="pt-3">
<template #title>Progress Slot</template>
<ProgressTimeline :items="items[0].children as any[]">
<template #item="{ item }">
<div
class="flex items-center justify-center w-10 h-10 rounded-full border border-white bg-slate-300 group-[.is-active]:bg-emerald-500 text-slate-500 group-[.is-active]:text-emerald-50 shadow shrink-0 md:order-1 md:group-odd:-translate-x-1/2 md:group-even:translate-x-1/2">
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" width="12" height="12">
<path d="M12 10v2H7V8.496a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5V12H0V4.496a.5.5 0 0 1 .206-.4l5.5-4a.5.5 0 0 1 .588 0l5.5 4a.5.5 0 0 1 .206.4V10Z"/>
</svg>
</div>
<div class="w-[calc(100%-4rem)] md:w-[calc(50%-2.5rem)] bg-white p-4 rounded border border-slate-200 shadow">
<div class="flex items-center justify-between space-x-2 mb-1">
<div class="font-bold text-slate-900">{{ item.title }}</div>
<time class="font-caveat font-medium text-amber-500">{{ item.time }}</time>
</div>
<div class="text-slate-500">{{ item.description }}</div>
</div>
</template>
</ProgressTimeline>
</ICard>
<ICard body-class="pt-3">
<template #title>Discussion</template>
<DiscussionTimeline :items="items[0].children as any[]"/>
</ICard>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import ICard from '@/ui/card/card.vue'
import DefaultTimeline from '@/views/components/timeline/default/DefaultTimeline.vue'
import MilestoneTimeline from '@/views/components/timeline/milestone/MilestoneTimeline.vue'
import ProgressTimeline from '@/views/components/timeline/progress/ProgressTimeline.vue'
import DiscussionTimeline from '@/views/components/timeline/discussion/DiscussionTimeline.vue'
import { Timeline } from '@/views/components/timeline/Timeline.ts'
export default defineComponent({
name: 'TimelineHome',
components: { DiscussionTimeline, ProgressTimeline, MilestoneTimeline, DefaultTimeline, ICard },
data()
{
return {
items: [
{
title: 'Shadcn UI',
children: [
{
title: 'Shadcn UI',
description: 'Learn Shadcn UI',
time: '2024-04-17',
type: 'opened'
},
{
title: 'Shadcn UI 002',
description: 'Learn Shadcn UI 002',
tip: 'Tip Shadcn UI 002',
time: '2024-04-17',
type: 'commented'
},
{
title: 'Shadcn UI 003',
description: 'Learn Shadcn UI 003',
tip: 'Tip Shadcn UI 003',
time: '2024-04-17',
type: 'closed'
}
]
},
{
title: 'Vue 3',
children: [
{
title: 'Vue 3',
description: 'Learn Vue 3',
time: '2024-04-17 10:00:00'
}
]
}
] as Timeline[]
}
}
})
</script>

0 comments on commit 39a1b6c

Please sign in to comment.