feat(site): added component version prompting (#977)

This commit is contained in:
yoyo 2023-11-30 17:11:25 +08:00 committed by GitHub
parent 162a267728
commit cd9304bcdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 240 additions and 3 deletions

View File

@ -0,0 +1,192 @@
<template>
<span v-if="currentStageComputed" class="version-tip">
<div v-if="renderType === 'alert'">
<tiny-alert :type="alertTypeComputed" :closable="false">
<template #description>
<span>{{ tipComputed }}</span>
</template>
</tiny-alert>
</div>
<span v-if="renderType === 'tag'">
<tiny-tooltip
effect="light"
placement="top-start"
:open-delay="500"
:content="tipComputed"
:disabled="!tipComputed"
>
<tiny-tag size="mini" effect="dark" :type="tagTypeComputed">{{ currentStageComputed }}</tiny-tag>
</tiny-tooltip>
</span>
</span>
</template>
<script lang="ts">
import type { PropType } from 'vue'
import { defineComponent, computed } from 'vue'
import { Tag as TinyTag, Alert as TinyAlert, Tooltip as TinyTooltip } from '@opentiny/vue'
import { $t2 } from '../../i18n/index'
enum STAGE {
experimental = 'experimental',
stable = 'stable',
deprecated = 'deprecated',
removed = 'removed'
}
interface IStageVersionMetaData {
version: string
}
interface IVersionMetaData {
[STAGE.experimental]?: IStageVersionMetaData | string
[STAGE.stable]?: IStageVersionMetaData | string
[STAGE.deprecated]?: IStageVersionMetaData | string
[STAGE.removed]?: IStageVersionMetaData | string
}
interface Ii18nString {
'zh-CN': string
'en-US': string
}
const alertTypeMap = {
[STAGE.removed]: 'error',
[STAGE.deprecated]: 'error',
[STAGE.experimental]: 'warning',
[STAGE.stable]: 'info'
}
const tagTypeMap = {
[STAGE.removed]: 'danger',
[STAGE.deprecated]: 'danger',
[STAGE.experimental]: 'warning',
[STAGE.stable]: 'info'
}
const cnDesMap = {
[STAGE.experimental]: '处于测试阶段',
[STAGE.stable]: '自 v{version} 起稳定提供',
[STAGE.deprecated]: '从 v{version} 开始被废弃',
[STAGE.removed]: '于 v{version} 移除'
}
const enDesMap = {
[STAGE.experimental]: 'in beta',
[STAGE.stable]: 'stable since v{version}',
[STAGE.deprecated]: 'deprecated since v{version}',
[STAGE.removed]: 'removed in v{version}'
}
// deprecatedexperimentalbriefStage
export default defineComponent({
components: {
TinyTag,
TinyAlert,
TinyTooltip
},
props: {
metaData: {
type: Object as PropType<IVersionMetaData>,
default: () => ({})
},
renderType: {
type: String as PropType<'tag' | 'alert'>,
default: 'alert'
},
tipSubject: {
type: String as PropType<'component' | 'api'>,
default: 'component'
},
stages: {
type: Array as PropType<STAGE[]>,
default: () => [STAGE.experimental, STAGE.deprecated, STAGE.removed]
},
alertType: {
type: String
},
tagType: {
type: String
},
briefStage: {
type: Object as PropType<STAGE>
},
tip: {
type: Object as PropType<Ii18nString>
},
extendTip: {
type: Object as PropType<Ii18nString>
}
},
setup(props) {
const isInStage = (stage: STAGE) => Boolean(props.metaData[stage]) && props.stages.includes(stage)
const getVersion = (stage: STAGE) => {
if (!props.metaData[stage]) return ''
if (typeof props.metaData[stage] === 'string') {
return props.metaData[stage] as string
} else {
return (props.metaData[stage] as IStageVersionMetaData).version
}
}
const currentStageComputed = computed(() => {
if (props.briefStage) {
return props.briefStage
}
return [STAGE.deprecated, STAGE.experimental].find(isInStage)
})
const generateDes = (desMap: typeof cnDesMap) => {
const isFilterExperimental = isInStage(STAGE.deprecated) || isInStage(STAGE.stable)
const goingStages = Object.entries(desMap).filter(([stage]) => {
let isPicked = isInStage(stage as STAGE)
if (stage === STAGE.experimental) {
isPicked = isPicked && !isFilterExperimental
}
return isPicked
})
return goingStages.map(([stage, des]) => des.replace('{version}', getVersion(stage as STAGE))).join('')
}
const tipComputed = computed(() => {
if (props.tip) return $t2(props.tip['zh-CN'], props.tip['en-US']) as string
if (!props.metaData) return ''
const vertionDesZnCn = generateDes(cnDesMap)
const znChTip = `${props.tipSubject === 'component' ? '组件' : '特性'}${vertionDesZnCn}${props.extendTip?.['zh-CN'] || ''}`
const vertionDesEnUs = generateDes(enDesMap)
const enUsTip = `This ${props.tipSubject === 'component' ? 'component' : 'feature'} is ${vertionDesEnUs}. ${props.extendTip?.['en-US'] || ''}`
return $t2(znChTip, enUsTip) as string
})
const alertTypeComputed = computed(() => {
if (props.alertType) return props.alertType
return currentStageComputed.value ? alertTypeMap[currentStageComputed.value] : 'error'
})
const tagTypeComputed = computed(() => {
if (props.tagType) return props.tagType
return currentStageComputed.value ? tagTypeMap[currentStageComputed.value] : 'error'
})
return {
tipComputed,
currentStageComputed,
alertTypeComputed,
tagTypeComputed
}
}
})
</script>

View File

@ -8,6 +8,11 @@
<div class="ti-fi-1 ti-w0 ti-rel cmp-container">
<!-- 一个组件的文档: 描述md + demos + apis -->
<div class="markdown-body markdown-top-body" size="medium" v-html="cmpTopMd"></div>
<version-tip
v-if="currJson.metaData || currJson.versionTipOption"
:metaData="currJson.metaData"
v-bind="currJson.versionTipOption">
</version-tip>
<template v-if="currJson?.demos?.length > 0">
<div class="all-demos-container">
<h2 class="ti-f30 ti-fw-normal !ti-mb20">{{ $t('yan-shi') }}</h2>
@ -66,6 +71,13 @@
<td>
<a v-if="row.demoId" @click="jumpToDemo(row.demoId)">{{ row.name }}</a>
<span v-else>{{ row.name }}</span>
<version-tip
v-if="row.metaData || row.versionTipOption"
:metaData="row.metaData"
v-bind="row.versionTipOption"
renderType="tag"
tipSubject="api">
</version-tip>
</td>
<td v-if="!key.includes('slots')">
<a
@ -134,6 +146,7 @@ import { router } from '@/router.js'
import { Collapse, CollapseItem } from '@opentiny/vue'
import { faqMdConfig, staticDemoPath, getWebdocPath } from './cmpConfig'
import AsyncHighlight from './async-highlight.vue'
import VersionTip from './VersionTip.vue'
export default defineComponent({
name: 'CmpPageVue',
@ -143,7 +156,8 @@ export default defineComponent({
TinyButtonGroup: ButtonGroup,
TinyCollapse: Collapse,
TinyCollapseItem: CollapseItem,
AsyncHighlight
AsyncHighlight,
VersionTip
},
directives: {
loading: Loading.directive
@ -436,6 +450,9 @@ table.api-table {
border-bottom: 1px solid rgb(239, 239, 245);
padding: 12px;
line-height: 1.5;
.version-tip {
margin-left: 6px;
}
}
}

View File

@ -80,8 +80,17 @@
@collapse-change="collapseChange"
>
<template #default="{ data }">
<tiny-tag v-if="data?.mode?.includes('mobile-first')" effect="plain" class="ti-mr6">多端</tiny-tag>
<span>{{ data.label }}</span>
<div class="node-name-container">
<tiny-tag v-if="data?.mode?.includes('mobile-first')" effect="plain">多端</tiny-tag>
<span class="node-name-label">{{ data.label }}</span>
<tiny-tag
v-if="data.mark?.text"
class="node-float-tip"
effect="dark"
:type="data.mark?.type">
{{ data.mark.text}}
</tiny-tag>
</div>
</template>
</tiny-tree-menu>
</div>
@ -282,6 +291,10 @@ export default defineComponent({
}
.main-menu.tiny-tree-menu {
.tiny-tree-node__content-box {
min-width: 0;
}
height: calc(100% - var(--layout-api-mode-height));
.tiny-tree {
height: calc(100% - var(--layout-tree-menu-input-height));
@ -289,6 +302,21 @@ export default defineComponent({
}
.tree-node-name {
line-height: 1.5;
.node-name-container {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
gap: 6px;
.node-name-label {
flex-grow: 0;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
& > .tiny-input .tiny-input__inner {
height: var(--layout-tree-menu-input-height);